<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raghu Bharadwaj</title>
    <description>The latest articles on DEV Community by Raghu Bharadwaj (@raghu_bharadwaj_404e60eb0c).</description>
    <link>https://dev.to/raghu_bharadwaj_404e60eb0c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1782496%2Ff6a2f0b0-5d25-4cfc-99b7-83f5e8326288.jpg</url>
      <title>DEV Community: Raghu Bharadwaj</title>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raghu_bharadwaj_404e60eb0c"/>
    <language>en</language>
    <item>
      <title>Linux Kernel CVEs: What to Patch by Device (4 – 10 Oct 2026)</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sat, 10 Oct 2026 17:05:53 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/linux-kernel-cves-what-to-patch-by-device-4-10-oct-2026-24jp</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/linux-kernel-cves-what-to-patch-by-device-4-10-oct-2026-24jp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on TECH VEDA: &lt;a href="https://www.techveda.live/2026/10/10/linux-kernel-cves-10-oct-2026/" rel="noopener noreferrer"&gt;Linux Kernel CVEs: What to Patch by Device (4 – 10 Oct 2026)&lt;/a&gt;. This is a weekly series. Every CVE below was read from the CVE Program record, and the branch targets were checked against kernel.org.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The kernel CNA (the group that assigns Linux kernel CVE IDs) published 220 Linux kernel CVEs from 4 to 10 October 2026. 2 are rated CRITICAL (score 9.8), and both are in the software RDMA drivers: &lt;code&gt;CVE-2026-98323&lt;/code&gt; in siw and &lt;code&gt;CVE-2026-98365&lt;/code&gt; in rxe. 50 more are rated HIGH and 168 have no CNA score. Fixes are released for almost all records. &lt;code&gt;CVE-2026-98375&lt;/code&gt; is fixed only in 7.3-rc7, which is not released yet, and &lt;code&gt;CVE-2026-98165&lt;/code&gt; and &lt;code&gt;CVE-2026-98376&lt;/code&gt; list no stable-branch fix. No record states that a bug is being exploited. The action is to update to the fixed version for your branch. Minimum safe versions: 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.55, and 7.2.9. &lt;code&gt;CVE-2026-98365&lt;/code&gt; lists no fix for 5.10, 5.15 and 6.1.&lt;/p&gt;

&lt;p&gt;This week has 220 records. Last week had 1 record. This post describes 11 of them and names a few more. The two CRITICAL records are in software RDMA drivers, which most phones, cars and medical devices do not use. Most records are narrow driver and protocol fixes, so which ones matter depends on what your product uses. Use this post to find the Linux kernel CVEs that apply to your device class, then use the version table to plan one update.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one action: update to the fixed version for your branch
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;uname -r&lt;/code&gt; and find your branch in the table. If your version is lower than the value in the second column, plan the update. Each value is the highest fixed version named by any of this week's records for that branch, so one update covers every record that lists a fix for that branch. Each value equals the newest release on its branch in the &lt;a href="https://www.kernel.org/" rel="noopener noreferrer"&gt;kernel.org&lt;/a&gt; release list on 10 October 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stable branch&lt;/th&gt;
&lt;th&gt;Update to at least&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5.10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.10.271&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 5.10.271 is the newest release. Many records name no 5.10 fix because the affected code is not in 5.10 or the fix was not applied to 5.10. &lt;code&gt;CVE-2026-98365&lt;/code&gt; lists no 5.10 fix.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.15&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.15.222&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 5.15.222 is the newest release. &lt;code&gt;CVE-2026-98365&lt;/code&gt; lists no 5.15 fix.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.1.189&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 6.1.189 is the newest release. &lt;code&gt;CVE-2026-98365&lt;/code&gt; lists no 6.1 fix.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.6.158&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 6.6.158 is the newest release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.12.112&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 6.12.112 is the newest release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.18&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.18.55&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longterm. 10 records published 7 to 9 Oct, for example &lt;code&gt;CVE-2026-98374&lt;/code&gt;, need 6.18.55. Most other records need 6.18.54. 6.18.55 is the newest release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7.2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.2.9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Current stable. The same records need 7.2.9. Most others need 7.2.8. 7.2.9 is the newest release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mainline&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.3-rc7 (not released yet)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.3-rc6 is the newest and does not have the fix for &lt;code&gt;CVE-2026-98375&lt;/code&gt;. The records checked for this post are fixed in 7.3-rc5 or earlier.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Branches that are not listed were not affected, or the fix was released before this window. Check the record for your branch. A record can list no fix for an older branch where the bug may exist. The record does not say whether that branch is exposed, so check your tree and consider a newer longterm branch. &lt;code&gt;CVE-2026-98375&lt;/code&gt; (xen/netfront) is fixed only in 7.3-rc7, and &lt;code&gt;CVE-2026-98165&lt;/code&gt; and &lt;code&gt;CVE-2026-98376&lt;/code&gt; list no stable-branch fix. The kernel.org list of maintained releases no longer includes 7.1, so a 7.1 kernel should move to 7.2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile and automotive
&lt;/h2&gt;

&lt;p&gt;Phones and vehicle units use Wi-Fi, Bluetooth and TCP. Fix the bugs that remote users or unprivileged local users can reach before other bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98339: Wi-Fi cfg80211 stale BSS entry removal
&lt;/h3&gt;

&lt;p&gt;The kernel CNA scores this record 8.8 HIGH, with an adjacent-network vector, no privileges and no user interaction. A BSS entry is the kernel record of one Wi-Fi network. When the access point a device is connected to moves to a channel that already has a BSS entry, &lt;code&gt;cfg80211&lt;/code&gt; removes the old entry. The lookup also required the same BSS type, so an entry with the IBSS capability bit was not removed. The next step then triggered &lt;code&gt;WARN_ON(!cmp)&lt;/code&gt;. The record says an access point or device controlled by an attacker can trigger this. The record text describes a kernel warning, which is lower than the score suggests. Use the score as the CNA's view and set your priority by reachability. The code is in &lt;code&gt;net/wireless/scan.c&lt;/code&gt; and the related setting is &lt;code&gt;CONFIG_CFG80211&lt;/code&gt;. It affects 5.4 and later. The fix is in 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98339" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98290: Bluetooth RFCOMM lock inversion in listener cleanup
&lt;/h3&gt;

&lt;p&gt;The score is 7.5 HIGH with an adjacent-network vector and high attack complexity. &lt;code&gt;rfcomm_sock_cleanup_listen()&lt;/code&gt; takes the child socket lock before &lt;code&gt;rfcomm_mutex&lt;/code&gt;. The RFCOMM worker takes them in the opposite order, so the kernel lock checker (lockdep) reports a possible deadlock. The impact is a possible deadlock, not memory corruption. RFCOMM carries serial-style classic Bluetooth profiles, so check whether your product enables it. The code is in &lt;code&gt;net/bluetooth/rfcomm/sock.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_BT_RFCOMM&lt;/code&gt;, which needs &lt;code&gt;CONFIG_BT&lt;/code&gt; and &lt;code&gt;CONFIG_BT_BREDR&lt;/code&gt;. It affects 5.15 and later. The fix is in 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. 5.10 is not affected. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98290" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98374: TCP use-after-free of retransmit_skb_hint
&lt;/h3&gt;

&lt;p&gt;The CNA has not scored this record. The record says a local unprivileged program that uses TCP Fast Open can make the kernel use freed memory in the TCP retransmit code. The record includes a KASAN trace (KASAN is a kernel memory error detector). The trigger also needs a specific network message to be delivered, so network conditions matter. This is memory corruption in the core TCP code. Check whether untrusted programs can run on your device. The code is in &lt;code&gt;net/ipv4/tcp_output.c&lt;/code&gt; and is built with IPv4 networking. It affects 5.11 and later. The fix is in 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.55 and 7.2.9. The record shows 5.10 as not affected. The 6.18.55 and 7.2.9 values in the table come from this record and nine others. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98374" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also check these records for phones and vehicle units. &lt;code&gt;CVE-2026-98255&lt;/code&gt; (not scored) fixes how TCP handles old ACKs. &lt;code&gt;CVE-2026-98256&lt;/code&gt; (7.8 HIGH), &lt;code&gt;CVE-2026-98258&lt;/code&gt; (7.8 HIGH), &lt;code&gt;CVE-2026-98260&lt;/code&gt; (7.8 HIGH) and &lt;code&gt;CVE-2026-98281&lt;/code&gt; (7.8 HIGH) fix exec, signal, POSIX timer and futex bugs that a local program can reach. &lt;code&gt;CVE-2026-98373&lt;/code&gt; (not scored) fixes a memory-management bug in mremap with huge pages. Read the records to see which branches have a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded and IoT
&lt;/h2&gt;

&lt;p&gt;Embedded boards use many network chips and wireless parts. Check the driver in your board configuration before you set the priority.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98239: Microchip LAN743x receive checksum use-after-free
&lt;/h3&gt;

&lt;p&gt;The score is 8.1 HIGH with a network vector and high attack complexity. When a packet spans more than one receive buffer, the driver writes &lt;code&gt;ip_summed&lt;/code&gt; through a pointer to a freed fragment. The record says multi-buffer receive can occur after a live MTU increase, so the risk depends on whether the MTU is changed while the system runs. The record also says it was not tested on real LAN743x hardware. The code is in &lt;code&gt;drivers/net/ethernet/microchip/lan743x_main.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_LAN743X&lt;/code&gt;, for the Microchip LAN743x and PCI11x1x PCI Express Ethernet devices. It affects 6.1 and later. The fix is in 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98239" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98348: Intel ipw2x00 libipw short association response
&lt;/h3&gt;

&lt;p&gt;The score is 7.1 HIGH with an adjacent-network vector. The length of the information elements is computed with an unsigned subtraction. A frame shorter than the fixed fields gives a length near 64 KiB, and the parser reads past the receive buffer. Both the ipw2100 and ipw2200 receive paths reach this function. Related records: &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98349" rel="noopener noreferrer"&gt;&lt;code&gt;CVE-2026-98349&lt;/code&gt;&lt;/a&gt; (same score, short beacon and probe responses) and &lt;code&gt;CVE-2026-98193&lt;/code&gt; (TKIP frames without a full MIC). The affected parts are old Intel PRO/Wireless 2100 and 2200BG PCI wireless cards, so this applies only to boards that still use them. The related setting is &lt;code&gt;CONFIG_LIBIPW&lt;/code&gt;, which &lt;code&gt;CONFIG_IPW2100&lt;/code&gt; and &lt;code&gt;CONFIG_IPW2200&lt;/code&gt; select. It affects 2.6.15 and later. The fix is in 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98348" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Boards with SDIO or NXP Wi-Fi modules should also check &lt;code&gt;CVE-2026-98189&lt;/code&gt; (not scored, a wilc1000 receive buffer write), &lt;code&gt;CVE-2026-98184&lt;/code&gt; (not scored), &lt;code&gt;CVE-2026-98185&lt;/code&gt; (not scored) and &lt;code&gt;CVE-2026-98186&lt;/code&gt; (not scored) in the mwifiex driver. These are Wi-Fi frame parsing fixes. Read the records to see which branches have a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud and datacenter
&lt;/h2&gt;

&lt;p&gt;The two CRITICAL records are here. This section also covers the SMB client, RDS and KVM on POWER hosts.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98323: RDMA siw out-of-bounds write (CRITICAL 9.8)
&lt;/h3&gt;

&lt;p&gt;The CNA scores this 9.8 CRITICAL with a network vector, no privileges and no user interaction. The siw driver can receive an extended header across more than one TCP callback. The next copy is limited by &lt;code&gt;hdrlen - MIN_DDP_HDR&lt;/code&gt; instead of the number of missing bytes. The copy then writes past the header and overwrites the receive state, including &lt;code&gt;fpdu_part_rcvd&lt;/code&gt;. A later callback uses a negative value as a copy offset, which gives an out-of-bounds write. The code runs only when the siw driver is in use. The code is in &lt;code&gt;drivers/infiniband/sw/siw/siw_qp_rx.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_RDMA_SIW&lt;/code&gt;, the software iWARP driver over TCP/IP. In practice the driver must be loaded and an siw device configured. The fix is in 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98323" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98365: RDMA rxe integer overflow and out-of-bounds access (CRITICAL 9.8)
&lt;/h3&gt;

&lt;p&gt;The score is 9.8 CRITICAL with a network vector. &lt;code&gt;mr_check_range()&lt;/code&gt; checks &lt;code&gt;iova + length&lt;/code&gt;, which can wrap to 0. The record says a remote peer can send RDMA requests that pass this range check by mistake. The code then uses a very large array index in &lt;code&gt;rxe_mr_copy_xarray()&lt;/code&gt;. This gives an out-of-bounds read or write and a kernel oops (a kernel error report). The record says an unauthenticated remote peer can trigger it. In practice an rxe device must be configured and used by an RDMA service. The code is in &lt;code&gt;drivers/infiniband/sw/rxe/rxe_mr.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_RDMA_RXE&lt;/code&gt;, the software RoCE driver, which needs 64-bit, PCI and InfiniBand support. The record says the bug exists since 4.8. The fix is listed only for 6.6.158, 6.12.112, 6.18.54 and 7.2.8. The record lists no fix for 5.10, 5.15 and 6.1. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98365" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98171: SMB client use-after-free in compound encrypted PDUs
&lt;/h3&gt;

&lt;p&gt;The score is 8.8 HIGH with a network vector and user interaction required. In &lt;code&gt;receive_encrypted_standard()&lt;/code&gt;, a stale &lt;code&gt;next_buffer&lt;/code&gt; pointer can cause a use-after-free. A bounds check also used the length before decryption, so &lt;code&gt;NextCommand&lt;/code&gt; could point into old data, and an integer overflow weakened the upper bound check. The server, or an attacker on the network path, must send crafted frames, so a client that mounts a share from an untrusted server or network is exposed. The code is in &lt;code&gt;fs/smb/client/smb2ops.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_CIFS&lt;/code&gt;, the SMB3 and CIFS client. It affects 4.19 and later. The fix is in 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. The record lists no 5.10 or 5.15 fix, and it does not say whether those branches are exposed. Several other SMB client records in this batch are HIGH, for example &lt;code&gt;CVE-2026-98169&lt;/code&gt;, &lt;code&gt;CVE-2026-98173&lt;/code&gt;, &lt;code&gt;CVE-2026-98174&lt;/code&gt; and &lt;code&gt;CVE-2026-98175&lt;/code&gt;. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98171" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98261: CIFS use-after-free in cifs_chan_skip_or_disable()
&lt;/h3&gt;

&lt;p&gt;The score is 8.1 HIGH with a network vector and high attack complexity. When a secondary channel is no longer supported by the server, the code drops the channel reference and then keeps using the freed server pointers. This is the SMB multichannel path. The code is in &lt;code&gt;fs/smb/client/smb2pdu.c&lt;/code&gt; and the related setting is &lt;code&gt;CONFIG_CIFS&lt;/code&gt;. It affects 6.8 and later, and the record also lists a 6.6 backport. The fix is in 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98261" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98257: RDS over InfiniBand connection deadlock
&lt;/h3&gt;

&lt;p&gt;The score is 7.5 HIGH with a network vector and an availability-only impact. When a peer negotiates an old protocol version, the handler calls &lt;code&gt;rds_conn_destroy()&lt;/code&gt; while it holds a lock that the shutdown work needs. The two workers wait on each other, and the RDS connection workqueues stop and do not recover. This is an availability problem only. The code is in &lt;code&gt;net/rds/ib_cm.c&lt;/code&gt;. The related setting is &lt;code&gt;CONFIG_RDS_RDMA&lt;/code&gt;, which needs &lt;code&gt;CONFIG_RDS&lt;/code&gt; and InfiniBand support. It affects 2.6.37 and later. The fix is in 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98257" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-98283: KVM PowerPC Book3S HV nested guest use-after-free
&lt;/h3&gt;

&lt;p&gt;The score is 8.8 HIGH with a local vector and a changed scope. &lt;code&gt;kvmhv_emulate_tlbie_all_lpid()&lt;/code&gt; drops &lt;code&gt;mmu_lock&lt;/code&gt; without holding a reference on the nested guest. The record says the free path is fully controlled by the L1 guest. A concurrent request can free the object while the host still uses it. This is a guest-to-host risk on shared PowerNV hosts that run nested guests. The code is in &lt;code&gt;arch/powerpc/kvm/book3s_hv_nested.c&lt;/code&gt;, in the powerpc architecture directory, so it is built only for POWER. The related setting is &lt;code&gt;CONFIG_KVM_BOOK3S_64_HV&lt;/code&gt;, which depends on &lt;code&gt;CONFIG_PPC_POWERNV&lt;/code&gt;. There is no x86 KVM record in this batch. It affects 4.20 and later. The fix is in 6.1.189, 6.6.158, 6.12.112, 6.18.54 and 7.2.8. See the &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98283" rel="noopener noreferrer"&gt;cve.org record&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also check &lt;code&gt;CVE-2026-98357&lt;/code&gt; (8.1 HIGH, network vector) in the iSER target code. The BPF records are &lt;code&gt;CVE-2026-98376&lt;/code&gt; (not scored; it lists no stable-branch fix), &lt;code&gt;CVE-2026-98378&lt;/code&gt;, &lt;code&gt;CVE-2026-98382&lt;/code&gt;, &lt;code&gt;CVE-2026-98383&lt;/code&gt; and &lt;code&gt;CVE-2026-98384&lt;/code&gt; (all not scored). Some BPF bugs need privilege to reach, so check whether unprivileged BPF is allowed on your hosts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Medical devices
&lt;/h2&gt;

&lt;p&gt;Connected clinical devices use Wi-Fi, Bluetooth, TCP/IP and network file shares. These records apply when the device uses the same code. For devices with Wi-Fi, such as patient monitors, check &lt;code&gt;CVE-2026-98339&lt;/code&gt;. Check &lt;code&gt;CVE-2026-98290&lt;/code&gt; only if the device uses classic Bluetooth RFCOMM. Many wearables use Bluetooth Low Energy, which does not use RFCOMM. For devices on a clinical network, check &lt;code&gt;CVE-2026-98374&lt;/code&gt; for TCP. A device that only mounts an SMB share with the kernel client is in scope for &lt;code&gt;CVE-2026-98171&lt;/code&gt; and &lt;code&gt;CVE-2026-98261&lt;/code&gt;, even if it never acts as a server. Devices built on Microchip LAN743x Ethernet should check &lt;code&gt;CVE-2026-98239&lt;/code&gt;. Check whether your device uses RDMA, RDS or POWER KVM. Most medical devices do not.&lt;/p&gt;

&lt;p&gt;Medical-device patching depends on validation and regulatory revalidation (US FDA postmarket cybersecurity guidance, EU MDR, IEC 62304). The action is to plan the stable update through the manufacturer's change-control process. Do not delay it without a documented risk assessment, and use compensating controls such as network segmentation and disabling unused services in the meantime.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check if these Linux kernel CVEs apply to you
&lt;/h2&gt;

&lt;p&gt;Ask three questions. First: which version do you run? Second: is the related setting enabled? Third: can an attacker reach the code?&lt;/p&gt;

&lt;p&gt;Version: run &lt;code&gt;uname -r&lt;/code&gt; and compare it with the table. The example output below is only an illustration. Your values will differ.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
6.6.150
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration: check the &lt;code&gt;CONFIG_*&lt;/code&gt; setting named in each CVE section. If the symbol is not set, the code is not built. A module must also be loaded before its code runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;zcat /proc/config.gz | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'CONFIG_(RDMA_SIW|RDMA_RXE|BT_RFCOMM|CFG80211|CIFS|LAN743X|RDS_RDMA)='&lt;/span&gt;
&lt;span class="go"&gt;CONFIG_CFG80211=m
CONFIG_CIFS=m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reachability decides which bugs to fix first. Fix remote or over-the-air bugs first. Fix local unprivileged bugs next. Fix guest-to-host bugs on shared hosts after that. Fix privileged or configuration-only bugs last. For the 168 records with no CNA score, use the same reachability order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The kernel CNA published 220 CVEs for 4 to 10 October 2026. 2 are CRITICAL, 50 are HIGH and 168 have no CNA score.&lt;/li&gt;
&lt;li&gt;Both CRITICAL records are in the software RDMA drivers: &lt;code&gt;CVE-2026-98323&lt;/code&gt; (siw) and &lt;code&gt;CVE-2026-98365&lt;/code&gt; (rxe). They matter only if &lt;code&gt;CONFIG_RDMA_SIW&lt;/code&gt; or &lt;code&gt;CONFIG_RDMA_RXE&lt;/code&gt; is set and in use.&lt;/li&gt;
&lt;li&gt;Minimum safe versions: 5.10.271, 5.15.222, 6.1.189, 6.6.158, 6.12.112, 6.18.55 and 7.2.9.&lt;/li&gt;
&lt;li&gt;Wi-Fi, Bluetooth, TCP and SMB client fixes matter most for phones, vehicles, wearables and clinical devices.&lt;/li&gt;
&lt;li&gt;Fixes are released for almost all records. &lt;code&gt;CVE-2026-98375&lt;/code&gt; needs 7.3-rc7, which is not released yet. No record states that a bug is being exploited.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How many Linux kernel CVEs were published from 4 to 10 October 2026?&lt;/strong&gt;&lt;br&gt;
The kernel CNA published 220 records in this window, according to NVD. 2 are CRITICAL, 50 are HIGH and 168 have no CNA score. The IDs run without gaps from CVE-2026-98165 to CVE-2026-98384.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which are the CRITICAL Linux kernel CVEs this week?&lt;/strong&gt;&lt;br&gt;
CVE-2026-98323 in the siw software iWARP driver and CVE-2026-98365 in the rxe software RoCE driver. Both have a CNA score of 9.8. Both matter only on systems that use these RDMA drivers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do the records say these bugs are being exploited?&lt;/strong&gt;&lt;br&gt;
No record states that a bug is being exploited. Fixes are released for almost all records, so the action is to schedule the stable update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I applied last week's minimum safe versions. Is that enough?&lt;/strong&gt;&lt;br&gt;
No. Last week's single record had lower fixed versions, for example 6.1.187 and 6.6.156 (see the previous edition). This week's versions are higher on every branch, so update again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does the table not show a fix for CVE-2026-98365 on 5.10, 5.15 and 6.1?&lt;/strong&gt;&lt;br&gt;
The record says the bug exists since 4.8, but it lists fixed versions only for 6.6, 6.12, 6.18 and 7.2. The record does not say whether the older branches are exposed. Check whether the rxe code exists in your tree and whether CONFIG_RDMA_RXE is set. If it is, move to a newer longterm branch or disable the driver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98323" rel="noopener noreferrer"&gt;CVE-2026-98323 on cve.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-98365" rel="noopener noreferrer"&gt;CVE-2026-98365 on cve.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/linux-cve-announce/" rel="noopener noreferrer"&gt;linux-cve-announce mailing list archive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/category/releases.html" rel="noopener noreferrer"&gt;kernel.org releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/process/cve.html" rel="noopener noreferrer"&gt;Linux kernel CVE process documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/kernel-cves/" rel="noopener noreferrer"&gt;TECH VEDA kernel CVE tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/2026/10/03/linux-kernel-cves-03-oct-2026/" rel="noopener noreferrer"&gt;Previous edition: Linux Kernel CVEs, 27 Sep – 3 Oct 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>embedded</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why judgment compounds more slowly—and more durably—than tool knowledge</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sun, 04 Oct 2026 17:33:37 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/tools-vs-fundamentals-which-engineering-skills-last-6dn</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/tools-vs-fundamentals-which-engineering-skills-last-6dn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Tool knowledge pays back in the first week, but each new version resets part of it, so little of it builds up. Judgment pays back more slowly because it builds on itself: every problem you understand makes the next one easier. It is also about the problem and not about the tool, so it stays useful when the tool changes. Learn the tool well enough to do the work, and also study the problem it solves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In embedded Linux work, a team uses a build system, which is a program that builds the software image for a product. A software image is the file that contains the whole system software. Yocto and Buildroot are two common build systems, and each comes with its own commands, file formats and rules.&lt;/p&gt;

&lt;p&gt;Suppose two engineers join different teams. Both learn the commands of their team's build system and can produce an image within a week. (This example is illustrative, not measured.)&lt;/p&gt;

&lt;p&gt;The second engineer also studies the questions that a product team has to answer, whatever tool it uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How long must this product be supported, and how long will the kernel and the other components it depends on be maintained?&lt;/li&gt;
&lt;li&gt;When a vulnerability is published, how do we learn whether we ship the affected component, and how fast must a fix reach customers?&lt;/li&gt;
&lt;li&gt;How will a fix reach devices already in the field safely, with signed updates, and what does the customer's domain require?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To answer these you must know exactly what shipped and be able to rebuild it. The build system is how you act on these decisions, not the decision itself. Small teams often have no separate security group, and choices such as key storage are hard to change later.&lt;/p&gt;

&lt;p&gt;A year later both teams change their build system. The first engineer must learn the new commands and also, for the first time, those questions. The second engineer learns only the new commands, and brings a year of answers that have already been tested against real releases.&lt;/p&gt;

&lt;p&gt;Now imagine that a vulnerability is published in a library. The first engineer can rebuild an image, but does not know whether the product ships that library, which version, or who must approve a fix.&lt;/p&gt;

&lt;p&gt;The second engineer has a record of every component in each released image and checks quickly. That engineer also asks whether an update can fail safely on a device that loses power halfway, and who holds the signing key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tool knowledge pays back in the first week. Judgment pays back more slowly, but it builds on itself and survives the tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What compounding means here
&lt;/h2&gt;

&lt;p&gt;Tool knowledge is knowing how to operate a tool: its commands, settings and file formats. Judgment is knowing which question matters, what is likely wrong, and what a change will do, in situations the manual does not cover.&lt;/p&gt;

&lt;p&gt;To compound means that each gain builds on the gains before it, as interest does. I use the word as a comparison, not as a measurement. I am not claiming that judgment grows at a number you can calculate, only that it has this shape: slow at the start, and larger each year because it rests on what came before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why tool knowledge pays back quickly but does not compound
&lt;/h2&gt;

&lt;p&gt;People make tools, and people change them. Commands are renamed, options are removed, and a project can replace a tool completely. Knowledge of those details is tied to one version, so some of it becomes less useful each time the tool changes. The next version starts partly from zero, which is why years of tool knowledge add up to less than they seem to.&lt;/p&gt;

&lt;p&gt;Tool knowledge is also written down in manuals, and an AI assistant can now find it in seconds.&lt;/p&gt;

&lt;p&gt;A large field study of customer-support agents found a similar effect in another job. Agents with an AI assistant and two months in the job performed as well as colleagues with more than six months in the job and no assistant, measured by issues resolved per hour. The authors report only suggestive evidence that the agents also learned from the assistant, and customer support is not engineering, so treat it as weak evidence.&lt;/p&gt;

&lt;p&gt;You still need the tools, because you cannot work without them, but knowing the tool is no longer enough by itself. What is still uncommon is described in &lt;a href="https://www.techveda.live/2026/08/19/engineering-skills-ai-cheap-scarce/" rel="noopener noreferrer"&gt;Your Code Got Cheap. Your Judgement Did Not.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why judgment compounds more slowly
&lt;/h2&gt;

&lt;p&gt;My current explanation is that judgment develops from useful experiences. An experience is useful when three things happen: you find the real cause of the problem, you see the result of your decision, and you understand why the result happened.&lt;/p&gt;

&lt;p&gt;That last step is what makes it build up. When you understand why a cause produced a result, you recognise the same pattern in the next problem and reach the cause faster. Each useful experience becomes the starting point of the next one, but you need many of them before the effect is noticeable, so the start is slow.&lt;/p&gt;

&lt;p&gt;Many hours of work contain none of these. For example, you may fix a failure by trying changes until it stops, and never learn which change mattered. Nothing is added, so nothing compounds. Why the person who made a decision often never sees its result is explained in &lt;a href="https://www.techveda.live/2026/09/06/work-years-are-not-practice-years/" rel="noopener noreferrer"&gt;Ten Years of Work Is Not Ten Years of Experience&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Research on professional intuition, which means fast expert judgment, names two conditions: an environment regular enough to predict, so that the same causes give the same results, and long practice in it with rapid, clear feedback. Feeling confident is not a reliable sign of being right.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Judgment compounds from useful experiences, not from hours of work alone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why judgment compounds more durably
&lt;/h2&gt;

&lt;p&gt;My view is that judgment is about the problem, and problems usually change more slowly than the tools used on them. Because the problem stays, what you learned about it carries over to the next tool instead of being reset. The product questions above are one example. Another is shared data.&lt;/p&gt;

&lt;p&gt;When two things can run at the same time, the data they share needs protection, or one of them can read it partly updated. Different systems protect it with different mechanisms, such as locks, atomic operations or disabling interrupts, and the mechanisms change over the years. The reason for the protection does not change.&lt;/p&gt;

&lt;p&gt;An engineer who knows the reason can usually read a new system's version of it much faster. This applies to related problems, not to every field. Reasoning about shared data is useful on the next system you work on, not in an unrelated job.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A new tool is a different method for the same job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where this argument has limits
&lt;/h2&gt;

&lt;p&gt;Some tool knowledge lasts. A tool that keeps its core behaviour stable for decades, such as the core of the POSIX shell, is worth the years spent learning it. Use the replacement test below on what you learn, not on the age of the tool.&lt;/p&gt;

&lt;p&gt;Tool-specific knowledge can also be a main part of the job. Knowing the quirks of the exact platform your product ships on can remain useful for as long as that product is sold. Learn it deeply in that case, and also learn why it is that way.&lt;/p&gt;

&lt;p&gt;Judgment can also be wrong, and it can go out of date when the problem itself changes. It compounds only while you keep checking it against results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tool lets you do the work. Judgment lets you decide whether the work is correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What to do this week
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run a replacement test.&lt;/strong&gt; List what you learned in the last six months, and for each item ask: if the tool were replaced next year, could I still use this? Mark each item yes or no, and learn the no items quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write down the problem behind your main tool.&lt;/strong&gt; Choose the tool you use most and write down what problem it solves, what you would do without it, and what you would check to know it worked. Then ask whether you could do the same job with a different tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here are examples for the replacement test. The command that signs an update is no, but why a device must verify the signature, and who guards the signing key, is yes. How your tool lists component versions is no, but how you find out whether a published vulnerability affects your product is yes.&lt;/p&gt;

&lt;p&gt;If you hire or train engineers, ask a candidate to explain a task they completed, then change the tool and ask what would remain the same.&lt;/p&gt;

&lt;p&gt;This is why TECH VEDA sessions are built around problem scenarios and not around the menus and windows of one tool. Each scenario is based on one problem, and you learn the tool while you solve it. The sessions are live and mentor-led. If you want to learn the build system and the product questions together, see the &lt;a href="https://www.techveda.live/embedded-linux-bsp-development/" rel="noopener noreferrer"&gt;Embedded Linux BSP Development training&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tool you learn this year will probably be replaced or changed. The problem it solved is likely to exist when you learn the next tool, and what you understood about it will carry forward.&lt;/p&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>career</category>
      <category>yocto</category>
    </item>
    <item>
      <title>Building Linux for a RISC-V Board — Part 2: Building OpenSBI Firmware and U-Boot from Source</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sun, 04 Oct 2026 17:17:49 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/building-linux-for-a-risc-v-board-part-2-building-opensbi-firmware-and-u-boot-from-source-28gi</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/building-linux-for-a-risc-v-board-part-2-building-opensbi-firmware-and-u-boot-from-source-28gi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Part 2 of this series replaces the firmware QEMU supplied in Part 1 with an OpenSBI firmware you build yourself, then puts U-Boot between it and the kernel. One build produces three firmware images that differ only in how each locates the next boot stage, and choosing between them is the decision this part is really about. By the end you will have booted Part 1's kernel through a chain you own end to end, and seen why the address 0x80200000 is agreed on by three separate projects with nothing checking it at runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.techveda.live/2026/09/28/risc-v-linux-boot-chain-part-1/" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt; cross-compiled a kernel, packed a BusyBox initramfs, booted both under QEMU and read the boot log line by line. All of it ran on firmware we did not build: the OpenSBI copy QEMU carries inside itself. That is where this part starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before you start
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;~/rv&lt;/code&gt; directory from Part 1, with &lt;code&gt;linux-6.12.111&lt;/code&gt; built and &lt;code&gt;initramfs.cpio.gz&lt;/code&gt; beside it, and the same cross-compiler and QEMU. Part 1's package list is not sufficient here: OpenSBI needs nothing new, but U-Boot builds host tools of its own and stops in the pylibfdt step or in &lt;code&gt;tools/mkimage&lt;/code&gt; without these.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;git build-essential swig libpython3-dev python3-setuptools python3-pyelftools libgnutls28-dev uuid-dev libncurses-dev
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/rv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiling takes about 15 minutes, and each QEMU run below is exited with &lt;code&gt;Ctrl-a&lt;/code&gt; then &lt;code&gt;x&lt;/code&gt; as in Part 1. Every command, path, configuration symbol and address here was checked against the upstream file that defines it, but the log excerpts show only the fields you should compare: version strings, device counts and byte sizes differ by host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why build the OpenSBI firmware yourself
&lt;/h2&gt;

&lt;p&gt;Part 1's banner said &lt;code&gt;OpenSBI v1.3&lt;/code&gt;. Nothing in the exercise chose that version: it is the copy vendored into the QEMU binary the distribution packaged, and changing it meant installing a different QEMU.&lt;/p&gt;

&lt;p&gt;On a product the firmware is a deliverable you own. It holds the physical memory protection regions that hide firmware from the kernel, the platform overrides for your silicon, and the set of SBI extensions your kernel will find. Part 1 showed the kernel probing for those at boot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[    0.000000] SBI TIME extension detected
[    0.000000] SBI IPI extension detected
[    0.000000] SBI RFENCE extension detected
[    0.000000] SBI SRST extension detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of those lines records one extension the kernel queried and the firmware answered for. The kernel does not assume an extension exists; it asks. An extension the firmware does not implement is a kernel feature that fails with no error message: without the &lt;code&gt;SRST&lt;/code&gt; extension, &lt;code&gt;poweroff&lt;/code&gt; does not power the board off. The firmware you built decides which exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the OpenSBI firmware
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/riscv-software-src/opensbi.git
raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;opensbi
raghu@techveda.org:~/rv/opensbi&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout v1.9
raghu@techveda.org:~/rv/opensbi&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;PLATFORM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;generic &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;riscv64-linux-gnu-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenSBI v1.9 was released on 1 July 2026. Checking out a tag rather than the branch tip matters more here than elsewhere: this is the code running at the highest privilege level on every hart, for the life of the system. &lt;code&gt;PLATFORM=generic&lt;/code&gt; is what to use unless your vendor says otherwise; it has no board-specific C file and configures itself from the device tree the previous stage passed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv/opensbi&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;build/platform/generic/firmware/&lt;span class="k"&gt;*&lt;/span&gt;.bin
build/platform/generic/firmware/fw_dynamic.bin
build/platform/generic/firmware/fw_jump.bin
build/platform/generic/firmware/fw_payload.bin
raghu@techveda.org:~/rv/opensbi&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/rv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The glob is deliberate: that directory also keeps object files, dependency files and linker scripts, so an unfiltered listing is noisy. Each image is there as an &lt;code&gt;.elf&lt;/code&gt; as well. Three firmwares from one build, same SBI implementation in all, differing in one respect: how each obtains the address of the next stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three OpenSBI firmware types, and how each locates the next stage
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;How it locates the next stage&lt;/th&gt;
&lt;th&gt;When you want it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FW_PAYLOAD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The next stage is compiled into the firmware image.&lt;/td&gt;
&lt;td&gt;The stage before OpenSBI can load only one blob.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FW_JUMP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jumps to an address fixed at build time; carries no payload.&lt;/td&gt;
&lt;td&gt;The previous stage loads both pieces where the firmware expects.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FW_DYNAMIC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reads the address at runtime from a structure the previous stage built.&lt;/td&gt;
&lt;td&gt;The previous stage loads both pieces and can say where it put them.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;FW_PAYLOAD&lt;/code&gt; takes &lt;code&gt;FW_PAYLOAD_PATH&lt;/code&gt; at build time and produces a single image. The cost is that every kernel rebuild is a firmware rebuild, which can mean re-signing firmware because an application-level change was merged.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FW_JUMP&lt;/code&gt; jumps to an address decided when it was compiled. &lt;code&gt;FW_JUMP_ADDR&lt;/code&gt; sets it absolutely; &lt;code&gt;FW_JUMP_OFFSET&lt;/code&gt; sets it as an offset from wherever OpenSBI was loaded, which keeps the firmware relocatable. The generic platform sets the offset, and one more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# platform/generic/objects.mk, the 64-bit arm
&lt;/span&gt;&lt;span class="nv"&gt;FW_JUMP_OFFSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x200000
&lt;span class="nv"&gt;FW_JUMP_FDT_OFFSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x2200000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So a &lt;code&gt;fw_jump&lt;/code&gt; image at 0x80000000 jumps to 0x80200000, and before jumping it copies the device tree to 0x82200000. That second number is easy to overlook: &lt;strong&gt;the device tree the next stage receives is not at the address the previous stage wrote it to&lt;/strong&gt;. It also sets a budget. The next stage is entered at 0x80200000 and the tree lands 32 MiB above it, so a payload larger than 32 MiB has its tail overwritten by the firmware's own copy of the tree. The order of events is what makes it that way round: the payload is already in RAM when OpenSBI starts, and the firmware copies the tree afterwards. Upstream states the constraint in the documentation for this variable and supplies a check for it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FW_DYNAMIC&lt;/code&gt; is the type to choose on a new design, and the mechanism is the reason. The previous stage builds a &lt;code&gt;struct fw_dynamic_info&lt;/code&gt; in memory and passes its address to the firmware in register &lt;code&gt;a2&lt;/code&gt;, 8-byte aligned on RV64. The structure carries a magic value, a version, the privilege mode to enter next, and the address to enter it at. Nothing is fixed at build time.&lt;/p&gt;

&lt;p&gt;QEMU does exactly this, which answers a question Part 1 left open: how did &lt;code&gt;-kernel&lt;/code&gt; work when the firmware was QEMU's own and knew nothing of our kernel? QEMU wrote the structure. Its RISC-V boot helper builds a &lt;code&gt;fw_dynamic_info&lt;/code&gt; with the next mode set to supervisor and the next address set to the kernel entry, stores it in the mask ROM just past the reset vector, and the reset vector's second instruction loads that address into &lt;code&gt;a2&lt;/code&gt;. Real boards do the same with a first-stage loader: U-Boot's SPL bundles OpenSBI's &lt;code&gt;fw_dynamic&lt;/code&gt; image and U-Boot proper into one FIT image and passes the firmware the address at which U-Boot was loaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boot Part 1's kernel on your own OpenSBI firmware
&lt;/h2&gt;

&lt;p&gt;One argument changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;qemu-system-riscv64 &lt;span class="nt"&gt;-machine&lt;/span&gt; virt &lt;span class="nt"&gt;-cpu&lt;/span&gt; rv64 &lt;span class="nt"&gt;-smp&lt;/span&gt; 2 &lt;span class="nt"&gt;-m&lt;/span&gt; 512M &lt;span class="nt"&gt;-nographic&lt;/span&gt; &lt;span class="nt"&gt;-bios&lt;/span&gt; opensbi/build/platform/generic/firmware/fw_dynamic.bin &lt;span class="nt"&gt;-kernel&lt;/span&gt; linux-6.12.111/arch/riscv/boot/Image &lt;span class="nt"&gt;-initrd&lt;/span&gt; initramfs.cpio.gz &lt;span class="nt"&gt;-append&lt;/span&gt; &lt;span class="s2"&gt;"console=ttyS0 rdinit=/init"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;-bios&lt;/code&gt;, QEMU loads your firmware and writes the structure for it. The banner confirms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OpenSBI v1.9
Platform Name             : riscv-virtio,qemu
Firmware Base             : 0x80000000
Domain0 Next Address      : 0x0000000080200000
Domain0 Next Mode         : S-mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now substitute &lt;code&gt;fw_jump.bin&lt;/code&gt; for &lt;code&gt;fw_dynamic.bin&lt;/code&gt;. Check your kernel against the 32 MiB budget first, because this is the layout that budget applies to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; linux-6.12.111/arch/riscv/boot/Image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under 33,554,432 bytes it boots. Over, and the firmware's copy of the tree lands inside the kernel, producing no console output at all. If your build is close to the line, stay with &lt;code&gt;fw_dynamic.bin&lt;/code&gt;, where QEMU places the tree out of the way instead.&lt;/p&gt;

&lt;p&gt;Within that budget the kernel boots, because &lt;code&gt;fw_jump&lt;/code&gt; ignores the structure QEMU prepared and jumps to a compile-time address that happens to be the same one. Three numbers, set in three projects, agree:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QEMU rounds the end of the firmware image up to a 2 MiB boundary to place a raw &lt;code&gt;-kernel&lt;/code&gt; binary. With firmware at 0x80000000 that is 0x80200000.&lt;/li&gt;
&lt;li&gt;OpenSBI's generic platform sets &lt;code&gt;FW_JUMP_OFFSET=0x200000&lt;/code&gt;, so the jump lands at the firmware base plus 2 MiB. Also 0x80200000.&lt;/li&gt;
&lt;li&gt;U-Boot's &lt;code&gt;CONFIG_TEXT_BASE&lt;/code&gt; for this board defaults to 0x80200000 when built for supervisor mode on RV64.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add U-Boot in supervisor mode
&lt;/h2&gt;

&lt;p&gt;A bootloader provides what firmware deliberately does not: a shell, storage drivers, a scriptable boot sequence and an environment that survives a reset. Build it for supervisor mode, because OpenSBI already runs in machine mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://source.denx.de/u-boot/u-boot.git
raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;u-boot
raghu@techveda.org:~/rv/u-boot&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout v2026.07
raghu@techveda.org:~/rv/u-boot&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;riscv64-linux-gnu- qemu-riscv64_smode_defconfig
raghu@techveda.org:~/rv/u-boot&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;riscv64-linux-gnu- &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
raghu@techveda.org:~/rv/u-boot&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/rv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;_smode_&lt;/code&gt; in the configuration name sets &lt;code&gt;CONFIG_RISCV_SMODE&lt;/code&gt;, which moves &lt;code&gt;CONFIG_TEXT_BASE&lt;/code&gt; from 0x80000000 to 0x80200000. The plain &lt;code&gt;qemu-riscv64_defconfig&lt;/code&gt; is the machine-mode build, linked at 0x80000000 so that it &lt;em&gt;replaces&lt;/em&gt; firmware rather than running under it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;qemu-system-riscv64 &lt;span class="nt"&gt;-machine&lt;/span&gt; virt &lt;span class="nt"&gt;-cpu&lt;/span&gt; rv64 &lt;span class="nt"&gt;-smp&lt;/span&gt; 2 &lt;span class="nt"&gt;-m&lt;/span&gt; 512M &lt;span class="nt"&gt;-nographic&lt;/span&gt; &lt;span class="nt"&gt;-bios&lt;/span&gt; opensbi/build/platform/generic/firmware/fw_jump.bin &lt;span class="nt"&gt;-kernel&lt;/span&gt; u-boot/u-boot.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U-Boot 2026.07 (Oct 04 2026 - 10:21:33 +0530)

Model: riscv-virtio,qemu
DRAM:  512 MiB
Core:  &amp;lt;n&amp;gt; devices, &amp;lt;m&amp;gt; uclasses, devicetree: board
Hit any key to stop autoboot:  2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press a key while that countdown runs. This configuration carries the distro boot defaults, so letting it expire scans for NVMe, virtio and SCSI devices and then attempts DHCP, printing a not-found line for each and pausing on the network attempt. It reaches the prompt anyway, but some of those targets load files into addresses used later in this part. &lt;code&gt;=&amp;gt;&lt;/code&gt; is U-Boot's prompt; commands shown with it below are typed there, not in the host shell.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;devicetree: board&lt;/code&gt; is the line that matters: U-Boot is using the tree firmware handed it, which is the one QEMU generated and OpenSBI relocated. That is why one U-Boot binary can describe a machine it was not built for. The failure values are &lt;code&gt;separate&lt;/code&gt; and &lt;code&gt;embed&lt;/code&gt;, which mean U-Boot fell back to a tree of its own and warns about it.&lt;/p&gt;

&lt;p&gt;U-Boot can also report which SBI implementation it is running on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; sbi
SBI &amp;lt;spec major&amp;gt;.&amp;lt;spec minor&amp;gt;
OpenSBI 1.9
Machine:
  Vendor ID 0
  Architecture ID 0
  Implementation ID 0
Extensions:
  SBI Base Functionality
  Timer Extension
  IPI Extension
  RFENCE Extension
  Hart State Management Extension
  System Reset Extension
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;1.9&lt;/code&gt; is the firmware you built, read back through an SBI call. The extension list is the same set of queries the kernel makes, run earlier by U-Boot, so an extension missing here will be missing in Linux too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load the kernel from U-Boot and start it
&lt;/h2&gt;

&lt;p&gt;U-Boot needs the kernel and the initramfs in memory. On a board they would come from storage, which is Part 3; for now QEMU's generic loader places files directly in RAM. First, the initramfs size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'0x%x\n'&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; %s initramfs.cpio.gz&lt;span class="si"&gt;)&lt;/span&gt;
0x&amp;lt;size &lt;span class="k"&gt;in &lt;/span&gt;hex&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;0x84000000 is what U-Boot itself calls &lt;code&gt;kernel_addr_r&lt;/code&gt;, so the kernel goes where U-Boot would have put it. The initramfs needs more care: U-Boot reserves 0x8c000000 through 0x8c300000 for &lt;code&gt;fdt_addr_r&lt;/code&gt;, &lt;code&gt;scriptaddr&lt;/code&gt;, &lt;code&gt;pxefile_addr_r&lt;/code&gt; and &lt;code&gt;ramdisk_addr_r&lt;/code&gt;, so 0x8f000000 keeps it clear of all four.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~/rv&lt;span class="nv"&gt;$ &lt;/span&gt;qemu-system-riscv64 &lt;span class="nt"&gt;-machine&lt;/span&gt; virt &lt;span class="nt"&gt;-cpu&lt;/span&gt; rv64 &lt;span class="nt"&gt;-smp&lt;/span&gt; 2 &lt;span class="nt"&gt;-m&lt;/span&gt; 512M &lt;span class="nt"&gt;-nographic&lt;/span&gt; &lt;span class="nt"&gt;-bios&lt;/span&gt; opensbi/build/platform/generic/firmware/fw_jump.bin &lt;span class="nt"&gt;-kernel&lt;/span&gt; u-boot/u-boot.bin &lt;span class="nt"&gt;-device&lt;/span&gt; loader,file&lt;span class="o"&gt;=&lt;/span&gt;linux-6.12.111/arch/riscv/boot/Image,addr&lt;span class="o"&gt;=&lt;/span&gt;0x84000000 &lt;span class="nt"&gt;-device&lt;/span&gt; loader,file&lt;span class="o"&gt;=&lt;/span&gt;initramfs.cpio.gz,addr&lt;span class="o"&gt;=&lt;/span&gt;0x8f000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; setenv bootargs &lt;span class="s1"&gt;'console=ttyS0 rdinit=/init'&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; booti 0x84000000 0x8f000000:0x&amp;lt;size &lt;span class="k"&gt;in &lt;/span&gt;hex&amp;gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;fdtcontroladdr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first argument is the address at which the kernel image was loaded. The second is the initramfs address and its size after a colon, mandatory for a raw ramdisk: a cpio archive carries no length field, so without it the kernel cannot be told how much to unpack. The third is the device tree, and &lt;code&gt;${fdtcontroladdr}&lt;/code&gt; holds the address of the tree U-Boot is itself using, which describes memory size, hart count and console node correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Moving Image from 0x84000000 to 0x80200000, end=0x&amp;lt;destination plus image_size&amp;gt;
## Flattened Device Tree blob at ...
   Booting using the fdt blob at 0x...
   Loading Device Tree to ..., end ... OK

Starting kernel ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That first line is expected. U-Boot relocated the kernel to the address U-Boot itself was linked at: its RISC-V image handling checks the Linux image header for the &lt;code&gt;RSC&lt;/code&gt; magic, refuses an image whose &lt;code&gt;image_size&lt;/code&gt; is zero, and relocates to the base of RAM plus the header's &lt;code&gt;text_offset&lt;/code&gt;. On RV64 that offset is 2 MiB — the PMD boundary Part 1 described — so the destination is 0x80200000.&lt;/p&gt;

&lt;p&gt;It is safe because U-Boot is no longer there: early in its own startup it relocates itself to the top of DRAM and runs from that copy. The device tree is copied to higher addresses for the same reason, which is why &lt;code&gt;${fdtcontroladdr}&lt;/code&gt; does not hold 0x82200000 by the time you use it. The ramdisk is not copied at all: this configuration sets &lt;code&gt;initrd_high&lt;/code&gt; to all ones, which selects the zero-copy path, so the initramfs is passed to the kernel where it already sits and no &lt;code&gt;Loading Ramdisk&lt;/code&gt; line appears.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[    0.000000] SBI implementation ID=0x1 Version=0x10009
...
=== userspace is up on riscv64, kernel 6.12.111 ===
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Version=0x10009&lt;/code&gt; is OpenSBI 1.9 in OpenSBI's own encoding, major in the upper sixteen bits and minor in the lower. The specification leaves the implementation-version encoding to the implementation, which is why the &lt;code&gt;SBI&lt;/code&gt; line and the &lt;code&gt;OpenSBI&lt;/code&gt; line in the &lt;code&gt;sbi&lt;/code&gt; output above are decoded differently by the same command. Part 1's line read &lt;code&gt;0x10003&lt;/code&gt;, OpenSBI 1.3. The change confirms the kernel is running on the firmware built here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this applies, and where it does not
&lt;/h2&gt;

&lt;p&gt;Everything above is specific to the QEMU &lt;code&gt;virt&lt;/code&gt; machine, OpenSBI's &lt;code&gt;generic&lt;/code&gt; platform, OpenSBI v1.9 and U-Boot v2026.07. Two boundaries matter enough to state plainly.&lt;/p&gt;

&lt;p&gt;On RV32 the generic platform sets &lt;code&gt;FW_JUMP_OFFSET&lt;/code&gt; and &lt;code&gt;FW_PAYLOAD_ALIGN&lt;/code&gt; to 0x400000 rather than 0x200000, and QEMU rounds the kernel load address up to 4 MiB instead of 2 MiB. Both assignments sit inside a conditional on the register width, so every address in this part shifts on a 32-bit target.&lt;/p&gt;

&lt;p&gt;The second boundary is the one this series exists to teach. Two of the three numbers that agree on 0x80200000 are offsets from the firmware base, so they follow the firmware when it moves. The third, U-Boot's &lt;code&gt;CONFIG_TEXT_BASE&lt;/code&gt;, is an absolute value in that board's Kconfig and follows nothing. On a board whose DRAM does not start at 0x80000000, it is the number you set yourself, and getting it wrong under &lt;code&gt;FW_JUMP&lt;/code&gt; produces a jump to an address that no longer holds the next stage. Nothing at runtime checks any of this, which is the practical argument for &lt;code&gt;FW_DYNAMIC&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common wrong turns
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Building U-Boot with &lt;code&gt;qemu-riscv64_defconfig&lt;/code&gt;.&lt;/strong&gt; It is the unsuffixed name, and on most architectures the plain defconfig is the right one, so it is a reasonable thing to reach for. Here it is the machine-mode build: linked at 0x80000000 while QEMU loads &lt;code&gt;-kernel&lt;/code&gt; at 0x80200000, and contending with OpenSBI for machine mode. The failure is early and produces little console output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leaving the size off the initramfs argument, or giving it in decimal.&lt;/strong&gt; These fail very differently. &lt;code&gt;booti 0x84000000 0x8f000000 ${fdtcontroladdr}&lt;/code&gt; is rejected outright: with no colon U-Boot cannot determine the format, prints &lt;code&gt;Wrong Ramdisk Image Format&lt;/code&gt; and stops before starting the kernel. A decimal size is the quiet one, because U-Boot parses numeric arguments as hexadecimal, so a size pasted from &lt;code&gt;stat&lt;/code&gt; is read as a far larger value and the command proceeds. That is why the &lt;code&gt;printf&lt;/code&gt; step is there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rebuilding the kernel and forgetting the firmware.&lt;/strong&gt; In every other configuration the kernel is a separate artifact, so the habit is correct everywhere except under &lt;code&gt;FW_PAYLOAD&lt;/code&gt;, where it fails with no error message: the firmware still holds the previous kernel and boots it. Put the firmware rebuild in the same script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The OpenSBI firmware is a deliverable you own: it decides the PMP regions, the platform overrides and the SBI extensions the kernel will find.&lt;/li&gt;
&lt;li&gt;One build produces three images differing only in how the next stage is located: embedded, fixed at build time, or passed at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FW_DYNAMIC&lt;/code&gt; reads a &lt;code&gt;struct fw_dynamic_info&lt;/code&gt; whose address arrives in &lt;code&gt;a2&lt;/code&gt;. QEMU builds that structure itself, which is why &lt;code&gt;-kernel&lt;/code&gt; works with firmware that knows nothing of your kernel.&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;FW_JUMP&lt;/code&gt; the generic platform copies the device tree 32 MiB above the next stage, which caps the payload at 32 MiB.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;booti&lt;/code&gt; relocates the kernel to the base of RAM plus the header's &lt;code&gt;text_offset&lt;/code&gt;, which is safe only because U-Boot has already moved itself to the top of DRAM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verify your boot chain
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The banner names the version you checked out. If it still shows Part 1's, &lt;code&gt;-bios&lt;/code&gt; is missing. A wrong path does not fall back silently: QEMU exits with &lt;code&gt;Unable to load the RISC-V firmware&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;U-Boot's banner reads &lt;code&gt;devicetree: board&lt;/code&gt;. &lt;code&gt;separate&lt;/code&gt; or &lt;code&gt;embed&lt;/code&gt; mean it fell back to a tree of its own.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sbi&lt;/code&gt; at the U-Boot prompt names &lt;code&gt;OpenSBI&lt;/code&gt; and your version, and lists at least Base, Timer, IPI, RFENCE and System Reset.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;booti&lt;/code&gt; prints a &lt;code&gt;Moving Image&lt;/code&gt; line whose destination is 0x80200000; the &lt;code&gt;end=&lt;/code&gt; value is that address plus the kernel's &lt;code&gt;image_size&lt;/code&gt;. &lt;code&gt;Bad Linux RISCV Image magic!&lt;/code&gt; means the address you gave does not hold an &lt;code&gt;Image&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The kernel line &lt;code&gt;SBI implementation ID=0x1 Version=...&lt;/code&gt; shows your firmware version. This confirms the chain, because the kernel is reporting the version returned by its own SBI call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Engineers who want this material as a structured programme rather than a series of posts can find it in TECH VEDA's &lt;a href="https://www.techveda.live/embedded-linux-yocto/" rel="noopener noreferrer"&gt;embedded Linux training&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next in this series
&lt;/h2&gt;

&lt;p&gt;Part 3 replaces the hand-typed addresses with storage: a virtio block device, a real root filesystem on it, and U-Boot booting it from a script rather than from arguments you retype.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do I have to build the OpenSBI firmware, or can I keep QEMU's?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
QEMU's bundled firmware is fine for learning, and Part 1 used it. It stops being fine once the version matters, because the only way to change it is to install a different QEMU. On hardware there is no bundled copy at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which OpenSBI firmware type should I use on a real board?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;FW_DYNAMIC&lt;/code&gt; if the stage before OpenSBI can load two binaries and say where the second went, which is the usual arrangement with a first-stage loader such as U-Boot SPL. &lt;code&gt;FW_PAYLOAD&lt;/code&gt; if that stage can load only one blob. &lt;code&gt;FW_JUMP&lt;/code&gt; works but depends on a build-time address staying correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does U-Boot move the kernel to the address U-Boot was linked at?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Because U-Boot is not there any more: it relocates itself to the top of DRAM early in its own startup. The kernel's destination is fixed by its image header, at the base of RAM plus a &lt;code&gt;text_offset&lt;/code&gt; of 2 MiB on RV64.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/2026/09/28/risc-v-linux-boot-chain-part-1/" rel="noopener noreferrer"&gt;Building Linux for a RISC-V Board — Part 1&lt;/a&gt; — the kernel build, the initramfs and the boot log, line by line.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/riscv-software-src/opensbi/blob/v1.9/docs/firmware/fw.md" rel="noopener noreferrer"&gt;OpenSBI firmware documentation&lt;/a&gt; — the firmware types and the &lt;code&gt;FW_JUMP&lt;/code&gt; address variables.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/riscv-software-src/opensbi/blob/v1.9/docs/platform/qemu_virt.md" rel="noopener noreferrer"&gt;OpenSBI on the QEMU virt platform&lt;/a&gt; — build commands and the &lt;code&gt;-bios&lt;/code&gt; and &lt;code&gt;-kernel&lt;/code&gt; combinations.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.u-boot.org/en/latest/board/emulation/qemu-riscv.html" rel="noopener noreferrer"&gt;U-Boot on QEMU RISC-V&lt;/a&gt; — the defconfig names and the SPL and FIT arrangement.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.u-boot.org/en/latest/usage/cmd/booti.html" rel="noopener noreferrer"&gt;U-Boot booti command&lt;/a&gt; — the argument syntax, including why a raw ramdisk needs an explicit size.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-base.adoc" rel="noopener noreferrer"&gt;RISC-V SBI base extension&lt;/a&gt; — the implementation and version queries, and why the implementation-version encoding is left to the implementation.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>riscv</category>
      <category>embedded</category>
      <category>kernel</category>
    </item>
    <item>
      <title>Android Automotive Kernel End-of-Life: How to Find the Date That Applies to Your Build</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Fri, 02 Oct 2026 04:06:24 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/android-automotive-kernel-end-of-life-how-to-find-the-date-that-applies-to-your-build-5fnj</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/android-automotive-kernel-end-of-life-how-to-find-the-date-that-applies-to-your-build-5fnj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;An Android Automotive kernel built on a certified Generic Kernel Image has two Google dates, and kernel.org's projection is neither of them. Each quarterly GKI release is deprecated about fifteen months after it is published: the September 2026 &lt;code&gt;android16-6.12&lt;/code&gt; release at 6.12.92 is deprecated from 1 January 2028.&lt;/p&gt;

&lt;p&gt;That date is the latest point at which to move to a newer release on the same branch, which the frozen kernel module interface normally allows without rebuilding vendor modules.&lt;/p&gt;

&lt;p&gt;The branch end of life, 1 July 2029 for &lt;code&gt;android16-6.12&lt;/code&gt;, is the date after which Google no longer supports the branch at all, and since kernel 6.6 Google sets it four years from upstream launch rather than six.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Teams building an infotainment head unit or a cockpit domain controller on Android Automotive OS are often asked the same question by a programme manager, a customer or a type-approval engineer. Until when will the Android Automotive kernel in this vehicle receive security fixes? The usual answer is read from the kernel.org longterm table, and for a certified GKI build it is the wrong date.&lt;/p&gt;

&lt;p&gt;This post sets out the dates that apply to an Android Automotive kernel and where each is published. It then explains how Google's dates are derived, which head units they bind, and gives a short procedure for establishing the date that applies to a shipped build.&lt;/p&gt;

&lt;p&gt;The scope is the Android common kernel branches from &lt;code&gt;android12-5.10&lt;/code&gt; to &lt;code&gt;android17-6.18&lt;/code&gt;, as listed on source.android.com and read on 2 October 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The published dates behind an Android Automotive kernel
&lt;/h2&gt;

&lt;p&gt;The first date is the upstream one. Kernel.org's releases page, read on 2 October 2026, lists six longterm series. Their projected end-of-life dates are December 2028 for 6.18 and 6.12, December 2027 for 6.6 and 6.1, and December 2026 for 5.15 and 5.10.&lt;/p&gt;

&lt;p&gt;The same page states that "each new longterm kernel usually starts with only a 2-year projected EOL that can be extended further if there is enough interest from the industry at large".&lt;/p&gt;

&lt;p&gt;The second date is Google's branch end of life. The Android common kernels page on source.android.com, last updated on 17 June 2026, carries a support-lifetime table for every Android common kernel branch (ACK) that Google maintains.&lt;/p&gt;

&lt;p&gt;It states that ACKs "might be supported for longer than the corresponding upstream stable kernel", in which case Google provides extended support until the date in the table. It also states that "when kernels are EOLed, they are no longer supported by Google and devices running them are considered to be vulnerable".&lt;/p&gt;

&lt;p&gt;The first four columns below are Google's table; the last column is added from kernel.org for comparison.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ACK branch&lt;/th&gt;
&lt;th&gt;Launch date&lt;/th&gt;
&lt;th&gt;Lifetime (years)&lt;/th&gt;
&lt;th&gt;Google EOL&lt;/th&gt;
&lt;th&gt;Kernel.org projected EOL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;android12-5.10&lt;/code&gt;, &lt;code&gt;android13-5.10&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2020-12-13&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2027-07-01&lt;/td&gt;
&lt;td&gt;December 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;android13-5.15&lt;/code&gt;, &lt;code&gt;android14-5.15&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2021-10-31&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2028-07-01&lt;/td&gt;
&lt;td&gt;December 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android14-6.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2022-12-11&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2029-07-01&lt;/td&gt;
&lt;td&gt;December 2027&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android15-6.6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2023-10-29&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2028-07-01&lt;/td&gt;
&lt;td&gt;December 2027&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android16-6.12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2024-11-17&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2029-07-01&lt;/td&gt;
&lt;td&gt;December 2028&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android17-6.18&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2025-11-30&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2030-07-01&lt;/td&gt;
&lt;td&gt;December 2028&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every Google date in that table equals the upstream launch date plus the stated lifetime, moved forward to the following 1 July. Google does not state this as a rule, but every row fits it. The gap between Google's date and kernel.org's therefore varies from about six months to about eighteen months, and the variation comes from kernel.org's projections rather than from Google's.&lt;/p&gt;

&lt;p&gt;The third date belongs to the build itself. Google does not ship one build per ACK branch. It publishes certified releases from it, each on its own git branch with its own deprecation date.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;android16-6.12&lt;/code&gt; release-builds page, last updated on 2 October 2026, lists the September 2026 release as branch &lt;code&gt;android16-6.12-2026-09&lt;/code&gt; at version 6.12.92. That release is "no longer respin eligible from 2027-04-01", except for security patches on explicit partner request, and is "deprecated from 2028-01-01. No respins allowed after this date."&lt;/p&gt;

&lt;h2&gt;
  
  
  How releases are cut from an Android common kernel branch
&lt;/h2&gt;

&lt;p&gt;Google's Android common kernels are downstream of kernel.org. When an upstream LTS is declared, a new ACK branch is branched from &lt;code&gt;android-mainline&lt;/code&gt; and named for the Android platform release and the kernel version, such as &lt;code&gt;android16-6.12&lt;/code&gt;. That branch then receives a merge from each upstream stable release, "normally done immediately after the LTS release is posted", in the words of the Android common kernels page.&lt;/p&gt;

&lt;p&gt;Each ACK branch passes through a development phase, a stabilisation phase and a frozen phase. Once the Kernel Module Interface (KMI) is frozen, it can be extended with new exported symbols but not broken, except where a serious security issue cannot be fixed any other way.&lt;/p&gt;

&lt;p&gt;This is the property that makes GKI a practical basis for an Android Automotive kernel. SoC and board support live in loadable vendor modules, and the core kernel can be replaced by a later release on the same branch without rebuilding them, provided the KMI generation number, the digit after &lt;code&gt;-androidNN-&lt;/code&gt; in &lt;code&gt;uname -r&lt;/code&gt;, is unchanged.&lt;/p&gt;

&lt;p&gt;The page states that if the KMI generation changes, "the modules must be rebuilt and updated synchronously with the kernel".&lt;/p&gt;

&lt;p&gt;The page also states the limit: "KMI compatibility isn't maintained between different GKI kernels", so moving from &lt;code&gt;android15-6.6&lt;/code&gt; to &lt;code&gt;android16-6.12&lt;/code&gt; means rebuilding every vendor module.&lt;/p&gt;

&lt;p&gt;From each ACK branch, Google publishes certified releases. The GKI release process page states that "GKI is released on a quarterly cadence post KMI freeze".&lt;/p&gt;

&lt;p&gt;Each quarterly release contains "a tested &lt;code&gt;boot.img&lt;/code&gt; that includes a Google inserted certificate to attest that the binaries were built from a known source code baseline". The page also publishes a calendar of check-in cut-off and preload-ready dates per branch, currently running to December 2026. The release tag carries the release branch name, in the form &lt;code&gt;android16-6.12-2025-12_r1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The release-builds page lists each release at a single LTS version. After publication, a release changes only through respins, which the release process page describes as builds containing "only the patches that are on top of the quarterly certified kernels that have been chosen".&lt;/p&gt;

&lt;p&gt;The release-builds page defines three stages. For its first six months a release is in the launch stage and accepts partner-requested respins. After that it enters the maintenance stage, in which it is "eligible for respin only by an explicit request from a partner for security patches cited in Android Security Bulletin (ASB)". Finally it is deprecated.&lt;/p&gt;

&lt;p&gt;The deprecated-builds page states the consequence: "These branches don't get security updates and aren't supported for deployment."&lt;/p&gt;

&lt;p&gt;The length of each release's life is visible in the dates. Each of the September 2026, June 2026, March 2026, December 2025 and September 2025 releases is deprecated on the first day of the sixteenth month after its release month, about fifteen months after the release is published.&lt;/p&gt;

&lt;p&gt;Google's kernel lifetime file, &lt;code&gt;kernel-lifetimes.xml&lt;/code&gt; in the &lt;code&gt;kernel/configs&lt;/code&gt; project, records the change: "when transitioning from monthly GKI releases to quarterly, the GKI lifetimes transitioned from 12-months to 15-months."&lt;/p&gt;

&lt;p&gt;The same file states that it is "used for enforcement of EOL by various tests", and that its dates "may indicate later dates than the official EOLs" by as much as one quarter, where enforcement was relaxed, for example during that transition.&lt;/p&gt;

&lt;p&gt;The release dates also follow the minimum kernel version that Google sets in the Android Security Bulletin. The release-builds page states: "When the LTS requirements cause the branch to be non-compliant, the branch is deprecated."&lt;/p&gt;

&lt;p&gt;The bulletin publishes the minimum in a section headed "Kernel LTS", as a table of Android launch version, kernel launch version and minimum update version. That section appears only in some bulletins. The December 2025 bulletin carries one row, a device launched on Android 12 with kernel 5.4 and a minimum update version of 5.4.292. The September 2026 bulletin has no such section.&lt;/p&gt;

&lt;p&gt;For a GKI release, the practical effect of the minimum is already published in advance as the release's deprecation date.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed: four-year branch lifetimes and fifteen-month releases
&lt;/h2&gt;

&lt;p&gt;The Android common kernels page states: "Beginning with kernel 6.6, the support lifetime for the stable kernels is 4 years."&lt;/p&gt;

&lt;p&gt;Before the change, &lt;code&gt;android14-6.1&lt;/code&gt;, launched upstream on 11 December 2022, carries a six-year lifetime and an end of life of 1 July 2029. After it, &lt;code&gt;android15-6.6&lt;/code&gt;, launched upstream on 29 October 2023, carries four years and an end of life of 1 July 2028.&lt;/p&gt;

&lt;p&gt;The result is an ordering that does not follow kernel age. The newer branch reaches Google's end of life one year before the older one, and on the same day as &lt;code&gt;android13-5.15&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second change concerns the releases. In 2025 the &lt;code&gt;android16-6.12&lt;/code&gt; branch had monthly releases.&lt;/p&gt;

&lt;p&gt;A copy of its release-builds page archived on 7 April 2026 lists the June, July and August 2025 releases at 6.12.23, 6.12.30 and 6.12.38, deprecated from 1 July, 1 August and 1 September 2026. Each of those lived twelve to thirteen months. The September 2025 release, also at 6.12.38, is deprecated from 1 January 2027, about fifteen months after publication.&lt;/p&gt;

&lt;p&gt;Two releases at the same LTS version therefore carry deprecation dates four months apart, because they fall on either side of the change from monthly to quarterly releases. On 2 October 2026 all three monthly releases appear only on the separate deprecated-builds page.&lt;/p&gt;

&lt;p&gt;The third change concerns the platform. The compatibility matrix on the Android common kernels page lists the kernels each Android release supports. Android 17 (2026) still lists &lt;code&gt;android12-5.10&lt;/code&gt; and &lt;code&gt;android13-5.10&lt;/code&gt;, but marks both "not supported in Android 17 QPR1 or higher".&lt;/p&gt;

&lt;p&gt;The current Android Automotive release notes list Android Automotive 26Q2 at API level 37, which is the Android 17 API level. A programme planning a platform upgrade through 2027 on a 5.10 kernel therefore has a platform end date as well as a kernel end date.&lt;/p&gt;

&lt;p&gt;For comparison with the Yocto side of the vehicle, NXP's S32 automotive BSP release &lt;code&gt;bsp48.0&lt;/code&gt;, tagged on 30 July 2026, uses a 6.12.92 kernel branch. That is the same LTS version as the September 2026 GKI release.&lt;/p&gt;

&lt;p&gt;The Yocto BSP has no published per-build deprecation date. Its maintenance period is limited by the kernel.org projection and by how often the vendor publishes a new branch. The GKI release at the same version has an explicit deprecation date, 1 January 2028. One model states the obligation and enforces it. The other requires the integrator to determine it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which head units Google's dates bind
&lt;/h2&gt;

&lt;p&gt;Google's release dates bind an Android Automotive kernel only when the device ships a certified GKI image. Whether an automotive device must do so is enforced by Google's own compliance test, &lt;code&gt;vts_gki_compliance_test.cpp&lt;/code&gt; in the VTS security test project.&lt;/p&gt;

&lt;p&gt;The test skips every device whose kernel is not arm64, with the message "Exempt from GKI test on non-arm64 kernel devices".&lt;/p&gt;

&lt;p&gt;For a device that declares itself automotive, it also skips the GKI check when the kernel version is below 5.15 or the device launched before Android 13. The comment in the source reads: "Skip for automotive devices if the kernel version is not &amp;gt;= 5.15 or the device is launched before Android T."&lt;/p&gt;

&lt;p&gt;The consequence for vehicle programmes is direct. An arm64 head unit that launched on Android 13 or later with a 5.15 or newer kernel is held to a certified GKI image or, from Android 14, an approved OEM-built GKI, and the release dates above apply to a certified GKI.&lt;/p&gt;

&lt;p&gt;A head unit on 5.10, on an x86_64 processor, or launched before Android 13 may ship a vendor-built kernel. For that kernel the per-release dates have no direct force. The governing date is whatever the vendor or Tier 1 supplier commits to. If the kernel was built from an ACK, Google's own fixes for it stop at the ACK end of life.&lt;/p&gt;

&lt;p&gt;The test also shows how certification is proven. It reads the boot partition, extracts the boot signature and fails with "The GKI image descriptor is not signed by an official key" if the signature does not verify against Google's keys.&lt;/p&gt;

&lt;p&gt;A kernel release string that contains &lt;code&gt;-android16-&lt;/code&gt; shows that the kernel came from an ACK. It does not show that the image is a certified GKI.&lt;/p&gt;

&lt;p&gt;The test further recognises an OEM-built GKI on Android 14 and later, identified by a release-string component matching &lt;code&gt;-abogki&lt;/code&gt; followed by a number, which it checks against a list of approved builds instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the date for a shipped Android Automotive kernel
&lt;/h2&gt;

&lt;p&gt;The procedure follows from the dates and conditions above. Establish whether the Android Automotive kernel is held to GKI, identify the release it ships, and then read the release date and the branch date. These checks run from the host over adb:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;adb shell &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-rm&lt;/span&gt;
&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;adb shell getprop ro.product.first_api_level
&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;adb shell pm has-feature android.hardware.type.automotive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The machine field from &lt;code&gt;uname -m&lt;/code&gt; shows whether the kernel is arm64; the VTS test accepts &lt;code&gt;aarch64&lt;/code&gt; or &lt;code&gt;armv8l&lt;/code&gt;. The first API level shows the Android release the device launched with, and 33 is Android 13. The feature query prints &lt;code&gt;true&lt;/code&gt; when the device declares itself automotive.&lt;/p&gt;

&lt;p&gt;Together these three answers tell you whether the compliance rule above applies to the Android Automotive kernel on the device under test.&lt;/p&gt;

&lt;p&gt;The release string from &lt;code&gt;uname -r&lt;/code&gt; begins with the upstream version, the Android release, the KMI generation and the commit, as in Google's documented example &lt;code&gt;6.6.30-android15-6-g86d10b30f51f&lt;/code&gt;, and may carry further suffixes. The upstream version gives the LTS version, and the Android release with the kernel version gives the ACK branch, &lt;code&gt;android15-6.6&lt;/code&gt; in that example.&lt;/p&gt;

&lt;p&gt;Look that branch up in the support-lifetime table for the branch end of life.&lt;/p&gt;

&lt;p&gt;Next, identify the release the Android Automotive kernel was built from. Map the LTS version to a release on the matching release-builds page, and check the deprecated-builds page as well.&lt;/p&gt;

&lt;p&gt;Because two releases can share an LTS version, as the two 6.12.38 releases show, ask the supplier for the GKI release tag the build was taken from, such as &lt;code&gt;android16-6.12-2025-12_r1&lt;/code&gt;. The tag names the release branch, and the release branch carries the deprecation date.&lt;/p&gt;

&lt;p&gt;Finally, read the patch level recorded in the boot image. For Android 16 GKI images, the release-builds page explains that the &lt;code&gt;os_version&lt;/code&gt; field in the boot image header is set to zero. Partners can instead put the operating system version and security patch level into the AVB footer, as the properties &lt;code&gt;com.android.build.boot.os_version&lt;/code&gt; and &lt;code&gt;com.android.build.boot.security_patch&lt;/code&gt;. On the host, with the boot image from the build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;avbtool info_image &lt;span class="nt"&gt;--image&lt;/span&gt; boot.img
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Google shows these properties in the form &lt;code&gt;Prop: com.android.build.boot.security_patch -&amp;gt; '2025-07-05'&lt;/code&gt;, and &lt;code&gt;avbtool info_image&lt;/code&gt; prints property descriptors as &lt;code&gt;Prop:&lt;/code&gt; lines. The value is the patch level the integrator declared for the boot image. Check that it matches the build that is actually flashed, but do not treat it as evidence of which kernel fixes are present. That comes from the release tag.&lt;/p&gt;

&lt;p&gt;The answer to the programme manager's question then has two parts. If the programme ships one GKI release and never updates it, the governing date is that release's deprecation date.&lt;/p&gt;

&lt;p&gt;If the programme always moves to a newer certified release on the same branch before the release it ships is deprecated, the governing date is the branch end of life, and each release date becomes the latest date for the next vehicle software update.&lt;/p&gt;

&lt;p&gt;After the branch end of life, the only routes are a move to a newer ACK branch, with every vendor module rebuilt, or a maintenance arrangement with the silicon vendor or Tier 1 supplier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes when reading Android Automotive kernel support
&lt;/h2&gt;

&lt;p&gt;The first mistake is to take the Android Automotive kernel's end of life from kernel.org alone. Kernel.org is the authoritative source for upstream longterm maintenance, and on a Yocto-built Linux system it often is the governing date.&lt;/p&gt;

&lt;p&gt;For a certified GKI build it is neither of Google's dates. The branch end of life is later on every row, and the release deprecation date is usually earlier.&lt;/p&gt;

&lt;p&gt;The second mistake is to assume that a newer Android Automotive kernel lasts longer. Under the six-year rule it did. Under the four-year rule, a supplier choosing between &lt;code&gt;android14-6.1&lt;/code&gt; and &lt;code&gt;android15-6.6&lt;/code&gt; for a 2026 start of production, on the assumption that newer means longer, would choose the branch that ends a year earlier.&lt;/p&gt;

&lt;p&gt;The third mistake is to treat the branch end of life as the date for an unmaintained build. The Android Automotive kernel in a shipped head unit is built from one release frozen at one LTS version.&lt;/p&gt;

&lt;p&gt;If no later release is ever taken, that release's deprecation date applies, and it is eighteen months before the branch date for the September 2026 &lt;code&gt;android16-6.12&lt;/code&gt; release.&lt;/p&gt;

&lt;p&gt;The reverse mistake also occurs. The release date is not always earlier: the July 2026 &lt;code&gt;android12-5.10&lt;/code&gt; release at 5.10.257 is deprecated from 1 November 2027, four months after its branch end of life of 1 July 2027. The page does not explain this, and this post does not offer an explanation. Read both dates.&lt;/p&gt;

&lt;p&gt;The fourth mistake is to read &lt;code&gt;-androidNN-&lt;/code&gt; in the release string as proof of a certified GKI, or to read the platform security patch level from &lt;code&gt;ro.build.version.security_patch&lt;/code&gt; as proof that the kernel is current. The first shows the kernel came from an ACK. The second describes the system image, not the kernel.&lt;/p&gt;

&lt;p&gt;The fifth mistake is to look for the kernel in the Android Automotive release notes.&lt;/p&gt;

&lt;p&gt;The Android Automotive 26Q2 notes, last updated on 27 September 2026, list eight new features and 180 addressed issues, covering the framework, car services, display safety and system UI. They do not mention a kernel version. Kernel support for Android Automotive is documented in the platform-wide kernel pages and in the VTS source, not in the automotive section.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not cover, and what was not verified
&lt;/h2&gt;

&lt;p&gt;Five limits apply. First, the compliance rule is read from the &lt;code&gt;main&lt;/code&gt; branch of the VTS source on 2 October 2026. The version of VTS that a particular programme was certified against may differ, and the post does not trace the rule back through earlier releases.&lt;/p&gt;

&lt;p&gt;Second, the Android Automotive kernel may not be the only kernel in the vehicle. Where Android Automotive OS runs as a guest under a hypervisor, the host or hypervisor and any safety domain beside it have their own maintenance positions, which these Android tables do not describe.&lt;/p&gt;

&lt;p&gt;Third, Google's dates describe Google's support. A silicon vendor or Tier 1 supplier may contract to maintain a kernel beyond them. Such contracts are not public, no supplier arrangement is named here, and no vehicle or manufacturer is attached to any kernel version in this post.&lt;/p&gt;

&lt;p&gt;Fourth, the two places Google publishes release dates do not always agree. The release-builds pages give dates per release; &lt;code&gt;kernel-lifetimes.xml&lt;/code&gt; gives dates per LTS version and states that its enforcement dates can be up to one quarter later.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;android16-qpr2-release&lt;/code&gt; branch it lists 6.12.23 with an end of life of 1 October 2026, against 1 July 2026 in the archived release page.&lt;/p&gt;

&lt;p&gt;Because it lists one date per LTS version, it cannot tell the two 6.12.38 releases apart; its 6.12.38 entry, 1 December 2026, is earlier than the September 2025 release's 1 January 2027. Record both and plan against the earlier one.&lt;/p&gt;

&lt;p&gt;Fifth, the minimum update version for any particular launch version was not established for this post. The "Kernel LTS" section was read in the December 2025 bulletin, and the September 2026 bulletin was confirmed to have none.&lt;/p&gt;

&lt;p&gt;For kernels that do not come from Google, the counterpart to this procedure is the three-clock check in &lt;a href="https://www.techveda.live/2026/08/10/soc-kernel-support-lapsed/" rel="noopener noreferrer"&gt;how to tell whether SoC kernel support has already lapsed&lt;/a&gt;. It compares the upstream end-of-life date, the vendor branch head date and the silicon longevity commitment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A certified GKI-based Android Automotive kernel has two Google dates: the release deprecation date and the ACK branch end of life. Kernel.org's projection is neither.&lt;/li&gt;
&lt;li&gt;Quarterly GKI releases are deprecated about fifteen months after publication. For a build that is never updated, that date usually comes first; for a programme that moves to a newer release on the same branch before each release it ships is deprecated, the branch end of life governs.&lt;/li&gt;
&lt;li&gt;Moving to a newer release on the same branch keeps the vendor modules. Moving to a newer ACK branch requires rebuilding all of them.&lt;/li&gt;
&lt;li&gt;Google's VTS source holds an automotive device to certified GKI (or an approved OEM-built GKI) only on arm64, with a 5.15 or newer kernel, and a launch on Android 13 or later.&lt;/li&gt;
&lt;li&gt;Since kernel 6.6, Google's branch lifetimes are four years rather than six, so &lt;code&gt;android15-6.6&lt;/code&gt; ends before &lt;code&gt;android14-6.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Identify an Android Automotive kernel build by its GKI release tag, not its LTS version: two &lt;code&gt;android16-6.12&lt;/code&gt; releases at 6.12.38 carry deprecation dates four months apart.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verification checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;adb shell uname -rm&lt;/code&gt; reports &lt;code&gt;aarch64&lt;/code&gt; (or &lt;code&gt;armv8l&lt;/code&gt;) and a release string containing &lt;code&gt;-androidNN-&lt;/code&gt;, and you have recorded the ACK branch and its end of life from the support-lifetime table.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ro.product.first_api_level&lt;/code&gt; and the automotive feature query have been recorded, and you know whether the device is held to certified GKI.&lt;/li&gt;
&lt;li&gt;The supplier has named the GKI release tag, the tag appears on the release-builds or deprecated-builds page, and you have recorded that release's deprecation date.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;avbtool info_image&lt;/code&gt; on the &lt;code&gt;boot.img&lt;/code&gt; from the build that is flashed shows a &lt;code&gt;com.android.build.boot.security_patch&lt;/code&gt; property that matches the build's documented patch level.&lt;/li&gt;
&lt;li&gt;For a 5.10-based build, the programme's target platform version is below Android 17 QPR1, or a kernel branch change is scheduled.&lt;/li&gt;
&lt;li&gt;The Android Automotive kernel end-of-life date recorded for the programme names its source page and the date that page was read.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which end-of-life date applies to an Android Automotive kernel built on GKI?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For a build that is never updated, the deprecation date of the GKI release it was taken from, which is usually the earlier of Google's two dates. For a programme that moves to a newer certified release on the same branch before each release it ships is deprecated, the end of life of the Android common kernel branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does android15-6.6 reach end of life before android14-6.1?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Google's table gives &lt;code&gt;android15-6.6&lt;/code&gt; a four-year lifetime and an end of life of 1 July 2028, and &lt;code&gt;android14-6.1&lt;/code&gt; a six-year lifetime and an end of life of 1 July 2029. The change to four years applies from kernel 6.6 onwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Must every Android Automotive head unit ship a certified GKI?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Google's VTS GKI compliance test skips non-arm64 devices, and skips automotive devices whose kernel is older than 5.15 or that launched before Android 13. Those devices may ship vendor-built kernels, to which the per-release dates do not directly apply.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which documents describe Android Automotive kernel support?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not the Android Automotive release notes, which do not mention a kernel version. Support is documented in the platform-wide Android common kernel and GKI release pages, and the automotive compliance rule is in Google's VTS source.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you maintain a vendor kernel or BSP for a long-lived product, TECH VEDA's &lt;a href="https://www.techveda.live/embedded-linux-bsp-development/" rel="noopener noreferrer"&gt;Embedded Linux BSP Development&lt;/a&gt; training covers board bring-up and BSP work.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/core/architecture/kernel/android-common" rel="noopener noreferrer"&gt;Android common kernels&lt;/a&gt;, source.android.com, last updated 17 June 2026 (primary; support-lifetime table, KMI rules and compatibility matrix)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/core/architecture/kernel/gki-android16-6_12-release-builds" rel="noopener noreferrer"&gt;android16-6.12 release builds&lt;/a&gt;, source.android.com, last updated 2 October 2026 (primary; releases, stages and deprecation dates)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/core/architecture/kernel/gki-android16-6_12-deprecated-builds" rel="noopener noreferrer"&gt;android16-6.12 deprecated builds&lt;/a&gt;, source.android.com, last updated 2 October 2026 (primary)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.archive.org/web/20260407120758/https://source.android.com/docs/core/architecture/kernel/gki-android16-6_12-release-builds" rel="noopener noreferrer"&gt;android16-6.12 release builds, archived 7 April 2026&lt;/a&gt; (primary, archived; deprecation dates of the 2025 monthly releases)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/core/architecture/kernel/gki-android12-5_10-release-builds" rel="noopener noreferrer"&gt;android12-5.10 release builds&lt;/a&gt;, source.android.com, last updated 2 October 2026 (primary)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/core/architecture/kernel/gki-releases" rel="noopener noreferrer"&gt;Generic Kernel Image (GKI) release process&lt;/a&gt;, source.android.com, last updated 17 June 2026 (primary; quarterly cadence and respins)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://android.googlesource.com/platform/test/vts-testcase/security/+/refs/heads/main/avb/vts_gki_compliance_test.cpp" rel="noopener noreferrer"&gt;vts_gki_compliance_test.cpp&lt;/a&gt;, AOSP VTS security tests, main branch (primary; automotive GKI compliance rule)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://android.googlesource.com/kernel/configs/+/refs/heads/android16-qpr2-release/kernel-lifetimes.xml" rel="noopener noreferrer"&gt;kernel-lifetimes.xml&lt;/a&gt;, AOSP kernel/configs, android16-qpr2-release branch (primary; per-version enforcement dates)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/security/bulletin/2025-12-01" rel="noopener noreferrer"&gt;Android Security Bulletin, December 2025&lt;/a&gt; (primary; "Kernel LTS" minimum update table)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://source.android.com/docs/automotive/start/releases/aaos-26q2" rel="noopener noreferrer"&gt;Android Automotive 26Q2 release notes&lt;/a&gt;, last updated 27 September 2026 (primary)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/about/versions/17/setup-sdk" rel="noopener noreferrer"&gt;Set up the Android 17 SDK&lt;/a&gt;, developer.android.com (primary; API level 37)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kernel.org/releases.html" rel="noopener noreferrer"&gt;Active kernel releases&lt;/a&gt;, kernel.org, read 2 October 2026 (primary; longterm projected end-of-life dates)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>automotive</category>
      <category>embedded</category>
      <category>android</category>
    </item>
    <item>
      <title>Open-Source Device CVEs: What to Patch by Vertical (September 2026)</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Fri, 02 Oct 2026 04:05:15 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/open-source-device-cves-what-to-patch-by-vertical-september-2026-o2f</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/open-source-device-cves-what-to-patch-by-vertical-september-2026-o2f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on TECH VEDA: &lt;a href="https://www.techveda.live/2026/10/02/open-source-device-cves-sep-2026/" rel="noopener noreferrer"&gt;Open-Source Device CVEs: What to Patch by Vertical (September 2026)&lt;/a&gt;. This is a monthly series covering the device stack beyond the Linux kernel.&lt;/p&gt;

&lt;p&gt;September 2026 brought 36 open-source device CVEs and advisories worth acting on across 14 packages: &lt;code&gt;U-Boot&lt;/code&gt;, &lt;code&gt;OpenSSL&lt;/code&gt;, &lt;code&gt;wolfSSL&lt;/code&gt;, &lt;code&gt;expat&lt;/code&gt;, &lt;code&gt;zlib&lt;/code&gt;, &lt;code&gt;libxml2&lt;/code&gt;, &lt;code&gt;BusyBox&lt;/code&gt;, &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;FFmpeg&lt;/code&gt;, &lt;code&gt;GStreamer&lt;/code&gt;, &lt;code&gt;WebKitGTK&lt;/code&gt;, &lt;code&gt;Chromium&lt;/code&gt;, &lt;code&gt;containerd&lt;/code&gt;, &lt;code&gt;BlueZ&lt;/code&gt;. Two of them are in the CISA Known Exploited Vulnerabilities catalog. Both are Chromium V8 bugs. A proof of concept is published for one zlib issue. Most items have a fix upstream. Several exist only as commits or release candidates, and BusyBox has no upstream fix yet. The action is to update each affected package to the fixed version, take your distribution's patched package or cherry-pick where there is no release, and rebuild the image. 14 packages are affected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the device stack beyond the kernel. It includes the bootloader, the C library, the TLS libraries, the media pipeline, the language runtimes and the container runtime that sit inside a shipped image. Which of these open-source device CVEs matter to you depends on what is in your image and your software bill of materials (SBOM). The reporting window is 1 to 30 September 2026.&lt;/p&gt;

&lt;p&gt;The EU Cyber Resilience Act requires manufacturers to keep an SBOM and to handle the known vulnerabilities in their products, so your SBOM is the list to check this report against. This month the largest groups of fixes were in the U-Boot network boot code, the TLS libraries, &lt;code&gt;libxml2&lt;/code&gt;, and Python.&lt;/p&gt;

&lt;p&gt;We report a package issue only when it meets one of three tests. The CVSS base score is 7.0 or higher, or the issue is in the CISA KEV catalog, or it is clearly reachable in a normal device build. Scores come from the source named for each item. Projects, NVD and the CISA ADP do not always agree, and we say so where the gap is large. We leave out disputed issues and issues that need unusual build options. Kernel CVEs are not here. The weekly kernel advisory covers them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-source device CVEs to update this month
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;CVE(s) / advisory&lt;/th&gt;
&lt;th&gt;Bug type&lt;/th&gt;
&lt;th&gt;Fixed version&lt;/th&gt;
&lt;th&gt;Verticals&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;U-Boot&lt;/td&gt;
&lt;td&gt;CVE-2026-15390, CVE-2026-74220, CVE-2026-74221, CVE-2026-74222, CVE-2026-71971, CVE-2026-74225, CVE-2026-71972, CVE-2026-71973&lt;/td&gt;
&lt;td&gt;Network boot parsing flaws: IP fragment reassembly (9.0 and 8.2), NFS READ and READLINK replies (8.2), a use-after-free in the lwIP wget client (8.2), DHCPv6 options (7.1). Two boot-time image parsers (BMP and SquashFS, 5.9 and 5.2) are listed for reachability only. See the note on scoring below the table&lt;/td&gt;
&lt;td&gt;2026.10-rc5 or later clears all but two. Final 2026.10 is not tagged yet. CVE-2026-15390 and CVE-2026-71972: commits only&lt;/td&gt;
&lt;td&gt;Embedded/IoT, Mobile/Automotive, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenSSL&lt;/td&gt;
&lt;td&gt;CVE-2026-84782&lt;/td&gt;
&lt;td&gt;DTLS retransmit reads from the wrong buffer offset: heap disclosure or crash (project severity High)&lt;/td&gt;
&lt;td&gt;4.0.3, 3.6.5, 3.5.9, 3.4.8. 3.0.23 is for premium support customers only&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Embedded/IoT, Cloud/Datacenter, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wolfSSL&lt;/td&gt;
&lt;td&gt;CVE-2026-93302, CVE-2026-89102, CVE-2026-89136&lt;/td&gt;
&lt;td&gt;Certificate and authentication checks that can be bypassed: trusted-peer match ignores the public key, OCSP multi-stapling accepts any chain certificate, unsolicited raw public key accepted (all 8.3, project CNA)&lt;/td&gt;
&lt;td&gt;5.9.4&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Embedded/IoT, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;expat&lt;/td&gt;
&lt;td&gt;CVE-2026-93990&lt;/td&gt;
&lt;td&gt;A lone UTF-16 high surrogate is accepted and changes the next character (7.5, integrity only)&lt;/td&gt;
&lt;td&gt;2.8.5&lt;/td&gt;
&lt;td&gt;Embedded/IoT, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zlib&lt;/td&gt;
&lt;td&gt;CVE-2026-85091&lt;/td&gt;
&lt;td&gt;Heap overflow in gzprintf() after a stalled non-blocking gzwrite() (7.4). Proof of concept is published&lt;/td&gt;
&lt;td&gt;No release. Fix is a commit. 1.3.2 is still the newest release and is affected&lt;/td&gt;
&lt;td&gt;Embedded/IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;libxml2&lt;/td&gt;
&lt;td&gt;CVE-2026-86138, CVE-2026-86139, CVE-2026-86140, CVE-2026-86142, CVE-2026-86143, CVE-2026-86144&lt;/td&gt;
&lt;td&gt;Six integer overflow, buffer overflow and XInclude flaws in parsing and serialising XML (7.3 to 7.8 NVD, local vector)&lt;/td&gt;
&lt;td&gt;2.15.4&lt;/td&gt;
&lt;td&gt;Embedded/IoT, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BusyBox&lt;/td&gt;
&lt;td&gt;CVE-2026-88830, CVE-2026-88832&lt;/td&gt;
&lt;td&gt;Heap overflow in the TLS test applet ssl_server (7.5) and in romfs volume ID parsing (7.3)&lt;/td&gt;
&lt;td&gt;No upstream fix found. The newest release, 1.38.0, is affected&lt;/td&gt;
&lt;td&gt;Embedded/IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;CVE-2026-19445, CVE-2026-19553, CVE-2026-82049&lt;/td&gt;
&lt;td&gt;Use-after-free in ssl servers that switch contexts in sni_callback (9.2). Hostname check silently skipped in wrap_bio() without server_hostname (7.6). tarfile filter bypass through a hard link to a symlink (8.4). All scored by the Python CNA with CVSS 4.0&lt;/td&gt;
&lt;td&gt;3.14.8, 3.13.16, 3.12.15, 3.11.17, 3.10.22, 3.15.0 (the tarfile issue is fixed on 3.13 and earlier only)&lt;/td&gt;
&lt;td&gt;Cloud/Datacenter, Embedded/IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFmpeg&lt;/td&gt;
&lt;td&gt;CVE-2026-30754, CVE-2026-96611&lt;/td&gt;
&lt;td&gt;Out-of-bounds write in the RTP muxer (8.8, CISA-ADP). Integer overflow in HEIF parsing (6.9, listed for reachability)&lt;/td&gt;
&lt;td&gt;8.1 for CVE-2026-30754. 9.0 for CVE-2026-96611; an 8.x backport is not confirmed&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GStreamer&lt;/td&gt;
&lt;td&gt;CVE-2026-85150, GStreamer-SA-2026-0081, GStreamer-SA-2026-0080&lt;/td&gt;
&lt;td&gt;RTSP Digest header NULL dereference, remote denial of service (7.5, Red Hat CNA). Out-of-bounds read and write in gst-libav audio with more than 64 channels (no CVE, no score). souphttpsrc forwards credentials on cross-origin redirects (no CVE, no score)&lt;/td&gt;
&lt;td&gt;1.28.7&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebKitGTK&lt;/td&gt;
&lt;td&gt;WSA-2026-0006&lt;/td&gt;
&lt;td&gt;One advisory bundling memory-safety and policy fixes in the web engine. The project gives no CVSS scores&lt;/td&gt;
&lt;td&gt;2.54.0&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chromium&lt;/td&gt;
&lt;td&gt;CVE-2026-85046, CVE-2026-87491&lt;/td&gt;
&lt;td&gt;In CISA KEV. Two V8 bugs, a type confusion (8.8) and an out-of-bounds write (8.8), both with active exploitation recorded by CISA&lt;/td&gt;
&lt;td&gt;Chrome 152.0.7977.82 and 153.0.8010.36 respectively&lt;/td&gt;
&lt;td&gt;Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;containerd&lt;/td&gt;
&lt;td&gt;CVE-2026-95837&lt;/td&gt;
&lt;td&gt;CRI checkpoint restore bypasses the destination security context (project severity Critical, no CVSS published)&lt;/td&gt;
&lt;td&gt;2.2.7 and 2.3.4&lt;/td&gt;
&lt;td&gt;Cloud/Datacenter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BlueZ&lt;/td&gt;
&lt;td&gt;CVE-2026-85218, CVE-2026-19774&lt;/td&gt;
&lt;td&gt;AVRCP stack overflow, adjacent radio range, user action needed (7.3). A2DP stream endpoint stack overflow, needs pairing (7.1). Both run in a root daemon&lt;/td&gt;
&lt;td&gt;No release. Commits only. 5.87 is the newest tag and is affected by the AVRCP issue&lt;/td&gt;
&lt;td&gt;Mobile/Automotive, Embedded/IoT, Medical&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A note on scoring. The U-Boot scores for &lt;code&gt;CVE-2026-74220&lt;/code&gt;, &lt;code&gt;CVE-2026-74221&lt;/code&gt;, &lt;code&gt;CVE-2026-74222&lt;/code&gt;, &lt;code&gt;CVE-2026-71971&lt;/code&gt; and &lt;code&gt;CVE-2026-74225&lt;/code&gt; come from the VulnCheck CNA, which also published the CVEs on 29 September. CISA adds only exploitation and automation labels to them. The &lt;code&gt;CVE-2026-15390&lt;/code&gt; score of 9.0 comes from the CERT-PL CNA. Its record says the fix is in version &lt;code&gt;2026.07&lt;/code&gt; and also lists &lt;code&gt;2026.07&lt;/code&gt; as affected. Those two statements conflict, so take the fix commit &lt;code&gt;b1aec609&lt;/code&gt; and do not rely on the version number. The Python scores use CVSS 4.0 only, which tends to give higher numbers than CVSS 3.1 for the same flaw. The GStreamer score is from Red Hat, and the GStreamer project itself says the flaw cannot cause code execution.&lt;/p&gt;

&lt;p&gt;The OpenSSL advisory of 29 September also lists &lt;code&gt;CVE-2026-84783&lt;/code&gt;, a use-after-free in the X.509 extension cache. The project rates it Moderate and it affects OpenSSL 4.0 only. Update to &lt;code&gt;4.0.3&lt;/code&gt; if you run 4.0. Other OpenSSL items in that advisory are rated Low, mostly in QUIC and in timing side channels. Check them only if your devices use QUIC or DTLS with the affected features.&lt;/p&gt;

&lt;p&gt;Other items we reviewed and left out of the table. &lt;code&gt;CVE-2026-19499&lt;/code&gt; in glibc (strfmon, 7.7 from the glibc CNA) needs an application that passes an attacker-controlled format to &lt;code&gt;strfmon&lt;/code&gt;, the CVE text says no network-facing impact is known, and we could not confirm the fixed release. &lt;code&gt;CVE-2026-78807&lt;/code&gt; in wpa_supplicant (7.1 from the CISA ADP) is local only, and we could not confirm a fixed version. An xz advisory, &lt;code&gt;GHSA-5qpq-xqfv-j9pg&lt;/code&gt;, fixed in &lt;code&gt;5.8.4&lt;/code&gt;, needs an unusual memory-allocation failure and affects only the &lt;code&gt;.lzma&lt;/code&gt; and &lt;code&gt;.lz&lt;/code&gt; formats. The containerd release also fixed three Moderate denial-of-service issues (&lt;code&gt;CVE-2026-53495&lt;/code&gt;, &lt;code&gt;CVE-2026-95838&lt;/code&gt;, &lt;code&gt;CVE-2026-53493&lt;/code&gt;). Two Mbed TLS CVEs published in September (&lt;code&gt;CVE-2026-25832&lt;/code&gt; and &lt;code&gt;CVE-2026-73064&lt;/code&gt;) belong to July advisories and score 3.7 and 2.9.&lt;/p&gt;

&lt;p&gt;Packages checked this month with nothing that met the tests: GnuTLS, OpenSSH, Dropbear, SQLite, curl, systemd, dnsmasq, NetworkManager, runc, Node.js, OpenJDK and Mesa. Mbed TLS had no advisory dated September. For curl, the nine CVEs listed on 2 September are all rated Low by the project except one Medium, so none is in the table, although the CISA ADP gives &lt;code&gt;CVE-2026-82208&lt;/code&gt; a 7.5. For these packages: D-Bus, GRUB2, musl, ConnMan, Avahi and Trusted Firmware-A, we checked the Debian tracker and the CVE records, and for some we also checked the project index. Two Trusted Firmware-A advisories, TFV-14 and TFV-15, had no public CVE record or publication date when we checked. Treat those six packages as a weaker negative than the others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Carried over from earlier months
&lt;/h2&gt;

&lt;p&gt;Several items were also flagged last month and are still open. BlueZ has published no release since &lt;code&gt;5.87&lt;/code&gt;. The LE Audio advisory &lt;code&gt;GHSA-9683-2chf-hfw9&lt;/code&gt; and the BASS advisory &lt;code&gt;GHSA-7wjj-8mrm-jhw4&lt;/code&gt; still show no patched version, and the August fixes for &lt;code&gt;CVE-2026-80186&lt;/code&gt; and &lt;code&gt;CVE-2026-80185&lt;/code&gt; are still commits only. The patch table in this post is the authoritative one for BlueZ.&lt;/p&gt;

&lt;p&gt;Last month we named U-Boot &lt;code&gt;2026.07&lt;/code&gt; as the practical baseline. This month's network-boot fixes landed in &lt;code&gt;2026.10-rc3&lt;/code&gt; to &lt;code&gt;2026.10-rc5&lt;/code&gt;, so &lt;code&gt;2026.07&lt;/code&gt; no longer clears the month. FFmpeg &lt;code&gt;8.1.3&lt;/code&gt; was released on 21 September. We could not confirm from a tag whether it contains the July fixes, so check its release notes. BusyBox &lt;code&gt;CVE-2026-38752&lt;/code&gt; to &lt;code&gt;CVE-2026-38755&lt;/code&gt; still have no fixed release. The SQLite use-after-free CVE we mentioned in July, &lt;code&gt;CVE-2026-51290&lt;/code&gt;, was rejected by its CNA on 31 July as not a security issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile and automotive
&lt;/h2&gt;

&lt;p&gt;On automotive SoCs that ship U-Boot, it runs first in the boot chain. This month the issues are in the network boot path. &lt;code&gt;CVE-2026-15390&lt;/code&gt; is an out-of-bounds write in IP fragment reassembly. It needs &lt;code&gt;CONFIG_IP_DEFRAG=y&lt;/code&gt; and an attacker on the same network segment. &lt;code&gt;CVE-2026-74220&lt;/code&gt; and &lt;code&gt;CVE-2026-74221&lt;/code&gt; are in NFS reply handling, &lt;code&gt;CVE-2026-74222&lt;/code&gt; is in the &lt;code&gt;wget&lt;/code&gt; client, and &lt;code&gt;CVE-2026-74225&lt;/code&gt; is in DHCPv6. All of them need a network boot feature to be enabled and an attacker who controls or imitates a boot server. If your production boot flow does not use network boot, the risk is low. Update to &lt;code&gt;2026.10-rc5&lt;/code&gt; or later, or cherry-pick the fix commits.&lt;/p&gt;

&lt;p&gt;Bluetooth is the exposed surface in a vehicle, because the head unit pairs with phones the manufacturer does not control. &lt;code&gt;CVE-2026-85218&lt;/code&gt; is a stack overflow in the BlueZ AVRCP controller code. A nearby device can trigger it, and the user must take part in the connection. &lt;code&gt;CVE-2026-19774&lt;/code&gt; is a stack overflow in the A2DP stream endpoint code and needs the attacker to pair first. Both run in &lt;code&gt;bluetoothd&lt;/code&gt;, which runs as root. There is no BlueZ release to move to. Use your distribution's patched package or cherry-pick the commits. Debian reports &lt;code&gt;5.87-4&lt;/code&gt; as carrying the A2DP fix.&lt;/p&gt;

&lt;p&gt;In the media pipeline, &lt;code&gt;CVE-2026-85150&lt;/code&gt; lets a remote peer crash a GStreamer RTSP server that has authentication enabled, or an RTSP client that talks to a malicious server. Advisory &lt;code&gt;GStreamer-SA-2026-0081&lt;/code&gt; covers &lt;code&gt;gst-libav&lt;/code&gt;: media with more than 64 audio channels writes outside the channel arrays. Update to &lt;code&gt;1.28.7&lt;/code&gt; for both. For FFmpeg, &lt;code&gt;CVE-2026-30754&lt;/code&gt; affects the RTP muxer only, so it matters if the device sends RTP streams built from untrusted input. Update to &lt;code&gt;8.1&lt;/code&gt; or later. &lt;code&gt;CVE-2026-96611&lt;/code&gt; parses HEIF and MOV images, so it is reachable from untrusted files. It is fixed in &lt;code&gt;9.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For OpenSSL, &lt;code&gt;CVE-2026-84782&lt;/code&gt; matters if your telematics or connectivity stack uses DTLS. It needs a write that is suspended partway through a handshake. Update to &lt;code&gt;3.6.5&lt;/code&gt;, &lt;code&gt;3.5.9&lt;/code&gt; or the release for your branch. For wolfSSL, the three CVEs affect certificate and authentication checks. Update to &lt;code&gt;5.9.4&lt;/code&gt;. Two of them depend on build options, so check your configuration. WebKitGTK &lt;code&gt;2.54.0&lt;/code&gt; fixes the engine issues in advisory &lt;code&gt;WSA-2026-0006&lt;/code&gt;. Update it if your head unit renders web content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded and IoT
&lt;/h2&gt;

&lt;p&gt;On small devices, the bootloader, the TLS library and the parsers handle untrusted input. For U-Boot, update to &lt;code&gt;2026.10-rc5&lt;/code&gt; or later if the device uses network boot, DHCPv6 or a &lt;code&gt;wget&lt;/code&gt; client, or mounts media a user can replace. The two lower-scored issues, &lt;code&gt;CVE-2026-71972&lt;/code&gt; (BMP splash images) and &lt;code&gt;CVE-2026-71973&lt;/code&gt; (SquashFS), matter only if the device parses an image from storage that an attacker can replace.&lt;/p&gt;

&lt;p&gt;For TLS, update OpenSSL for &lt;code&gt;CVE-2026-84782&lt;/code&gt; if the device uses DTLS, and update wolfSSL to &lt;code&gt;5.9.4&lt;/code&gt;. The wolfSSL issue &lt;code&gt;CVE-2026-89136&lt;/code&gt; affects only builds with raw public key support. That option is off by default but it is enabled by the &lt;code&gt;--enable-all&lt;/code&gt; and &lt;code&gt;--enable-distro&lt;/code&gt; configurations. &lt;code&gt;CVE-2026-93302&lt;/code&gt; affects builds that define &lt;code&gt;WOLFSSL_TRUST_PEER_CERT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;expat&lt;/code&gt; to &lt;code&gt;2.8.5&lt;/code&gt; and &lt;code&gt;libxml2&lt;/code&gt; to &lt;code&gt;2.15.4&lt;/code&gt;. The &lt;code&gt;libxml2&lt;/code&gt; flaws are scored with a local vector, so the risk depends on whether your application parses XML that comes from outside. The &lt;code&gt;zlib&lt;/code&gt; flaw has no release. It affects only code that calls &lt;code&gt;gzprintf()&lt;/code&gt; on a non-blocking write stream. Check whether your code does that, and apply the upstream commit if it does.&lt;/p&gt;

&lt;p&gt;BusyBox has no upstream fix for either item. &lt;code&gt;CVE-2026-88830&lt;/code&gt; is in the &lt;code&gt;ssl_server&lt;/code&gt; applet, which Red Hat describes as a test and debug tool that is not shipped in its package. Check whether your BusyBox build enables it. &lt;code&gt;CVE-2026-88832&lt;/code&gt; needs a crafted romfs image to be mounted. If you run Python on the device, update it for the &lt;code&gt;tarfile&lt;/code&gt; issue &lt;code&gt;CVE-2026-82049&lt;/code&gt; when you extract archives from outside, for example update bundles. Update BlueZ using the commits as described above if the device uses Bluetooth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud and datacenter
&lt;/h2&gt;

&lt;p&gt;For OpenSSL, &lt;code&gt;CVE-2026-84782&lt;/code&gt; applies to any DTLS endpoint. Update to &lt;code&gt;3.6.5&lt;/code&gt;, &lt;code&gt;3.5.9&lt;/code&gt; or &lt;code&gt;3.4.8&lt;/code&gt;. If you run OpenSSL 3.0 outside a premium support contract, ask your distribution for a backport. For OpenSSL 4.0, also update for &lt;code&gt;CVE-2026-84783&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Python has the largest set. &lt;code&gt;CVE-2026-19445&lt;/code&gt; lets a remote client crash an &lt;code&gt;ssl&lt;/code&gt; server, or call through a freed pointer, if its &lt;code&gt;sni_callback&lt;/code&gt; swaps the context and nothing else keeps the original context alive. Servers that wrap only the listening socket are not affected, and TLS clients are not affected. &lt;code&gt;CVE-2026-19553&lt;/code&gt; is the opposite case for clients: &lt;code&gt;wrap_bio()&lt;/code&gt;, &lt;code&gt;asyncio.create_connection()&lt;/code&gt; and &lt;code&gt;asyncio.loop.start_tls()&lt;/code&gt; skip hostname checks when &lt;code&gt;server_hostname&lt;/code&gt; is missing. The project says you can mitigate it by always passing a valid &lt;code&gt;server_hostname&lt;/code&gt;. Update to &lt;code&gt;3.14.8&lt;/code&gt;, &lt;code&gt;3.13.16&lt;/code&gt;, &lt;code&gt;3.12.15&lt;/code&gt;, &lt;code&gt;3.11.17&lt;/code&gt; or &lt;code&gt;3.10.22&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For containerd, &lt;code&gt;CVE-2026-95837&lt;/code&gt; is rated Critical by the project and affects only hosts where CRI checkpoint restore is used. Update to &lt;code&gt;2.2.7&lt;/code&gt; or &lt;code&gt;2.3.4&lt;/code&gt;. Those versions turn restore through &lt;code&gt;CreateContainer&lt;/code&gt; off by default. Containers that were restored from untrusted checkpoints should be stopped and recreated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Medical devices
&lt;/h2&gt;

&lt;p&gt;Connected medical devices draw their packages from the other stacks. The risk is whichever package is reachable from a network or parses untrusted clinical data. Bluetooth is the clearest case. Patient monitors, wearables and gateways use BlueZ to pair with sensors and phones. &lt;code&gt;CVE-2026-85218&lt;/code&gt; and &lt;code&gt;CVE-2026-19774&lt;/code&gt; run in a root daemon and have no tagged fix, so plan for the distribution package or the commits.&lt;/p&gt;

&lt;p&gt;For data and media, &lt;code&gt;libxml2&lt;/code&gt; and &lt;code&gt;expat&lt;/code&gt; parse XML that often carries HL7 or FHIR content, so update to &lt;code&gt;2.15.4&lt;/code&gt; and &lt;code&gt;2.8.5&lt;/code&gt;. FFmpeg and GStreamer handle imaging and endoscopy video: update FFmpeg to &lt;code&gt;8.1&lt;/code&gt; or later and GStreamer to &lt;code&gt;1.28.7&lt;/code&gt;. For device touchscreen interfaces, update WebKitGTK to &lt;code&gt;2.54.0&lt;/code&gt; and Chromium to the fixed builds. The two Chromium V8 issues are in the CISA KEV catalog, so a device that browses untrusted content has the highest priority here. For TLS, update OpenSSL and wolfSSL as listed in the table. For U-Boot, the network boot issues matter only where the service flow uses network boot.&lt;/p&gt;

&lt;p&gt;Medical-device updates go through validation and regulatory change control, including US FDA postmarket cybersecurity guidance, EU MDR and IEC 62304. The action is to schedule these updates through the device manufacturer's change-control process, and not to patch a deployed device in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check if it applies to you
&lt;/h2&gt;

&lt;p&gt;Three questions decide whether a row is your problem. First, is the package in your image and your SBOM? If it is not built into the product, its CVEs are not yours. Second, is the vulnerable feature built or enabled? Examples are &lt;code&gt;CONFIG_IP_DEFRAG&lt;/code&gt; in U-Boot, &lt;code&gt;WOLFSSL_TRUST_PEER_CERT&lt;/code&gt; in wolfSSL, and the &lt;code&gt;ssl_server&lt;/code&gt; applet in BusyBox. Third, is your version below the fixed version? Distributions often backport a fix without changing the upstream version number, so check your distribution changelog before you assume you are exposed. For packages with only a commit, compare the source tree with the commit instead of a version. These commands read two versions on a running device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;openssl version
&lt;span class="go"&gt;OpenSSL 3.5.8
&lt;/span&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="go"&gt;Python 3.13.15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, OpenSSL &lt;code&gt;3.5.8&lt;/code&gt; is below the fixed &lt;code&gt;3.5.9&lt;/code&gt;, and Python &lt;code&gt;3.13.15&lt;/code&gt; is below the fixed &lt;code&gt;3.13.16&lt;/code&gt;. Both updates apply, if the affected feature is in use. The output above is shortened and is an example, not a measured result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;September 2026 has 36 device-stack CVEs and advisories across 14 packages. Two are in the CISA KEV catalog, and both are Chromium V8 bugs.&lt;/li&gt;
&lt;li&gt;U-Boot has the largest group. Its network boot fixes are in &lt;code&gt;2026.10-rc5&lt;/code&gt; or later, so the &lt;code&gt;2026.07&lt;/code&gt; baseline we gave last month is no longer enough.&lt;/li&gt;
&lt;li&gt;BlueZ still has no release after &lt;code&gt;5.87&lt;/code&gt;. Use your distribution package or cherry-pick the commits.&lt;/li&gt;
&lt;li&gt;Check the build options. Several wolfSSL, U-Boot and BusyBox items apply only to specific configurations.&lt;/li&gt;
&lt;li&gt;Python and OpenSSL have new fixed releases on every maintained branch. Update them and rebuild.&lt;/li&gt;
&lt;li&gt;Some scores come from one scorer only. Use reachability to set your priority order, and do not rely on the number alone.&lt;/li&gt;
&lt;li&gt;Map each CVE to your SBOM, confirm the feature is built and your version is below the fix, then update the package and rebuild the image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What are open-source device CVEs?&lt;/strong&gt;&lt;br&gt;
They are security vulnerabilities in the open-source packages that ship inside a device image, such as the bootloader, the TLS libraries, the media pipeline, the language runtimes and the container runtime. This roundup covers that device stack and leaves the Linux kernel to a separate weekly report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are any of these being exploited right now?&lt;/strong&gt;&lt;br&gt;
Two of them are. CVE-2026-85046 and CVE-2026-87491 are Chromium V8 bugs that CISA added to the Known Exploited Vulnerabilities catalog on 4 and 9 September 2026. No other package in this roundup is in the catalog. A proof of concept is published for the zlib issue CVE-2026-85091, and we found no evidence of exploitation of it. Most items have a fix upstream, so the action is to schedule the update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is no BlueZ release with the fixes. What do I do?&lt;/strong&gt;&lt;br&gt;
Take your Linux distribution's patched BlueZ package, or cherry-pick the fix commits into your build. The newest upstream tag is 5.87, and it is affected by the AVRCP issue CVE-2026-85218. Moving to the newest tag does not clear the month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does last month's U-Boot advice not cover this month?&lt;/strong&gt;&lt;br&gt;
Last month we named U-Boot 2026.07 as the practical baseline. The network boot issues published on 29 September were fixed in 2026.10-rc3 to 2026.10-rc5, so 2026.07 does not include those fixes. Update to 2026.10-rc5 or later, or cherry-pick the commits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to patch every package in the table?&lt;/strong&gt;&lt;br&gt;
No. Patch the packages that are in your image and your SBOM, whose vulnerable feature is built or enabled, and whose version is below the fixed version. The three checks in the section above narrow the table to the rows that affect your product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does this relate to the Cyber Resilience Act and the SBOM?&lt;/strong&gt;&lt;br&gt;
The Cyber Resilience Act expects a manufacturer to keep an SBOM and to handle the known vulnerabilities in the product. Your SBOM is the list you compare this report against. That turns a general CVE feed into a short, specific set of updates for your image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;OpenSSL security advisory, 29 September 2026: &lt;a href="https://openssl-library.org/news/secadv/20260929.txt" rel="noopener noreferrer"&gt;openssl-library.org/news/secadv/20260929.txt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;U-Boot security notes: &lt;a href="https://docs.u-boot.org/en/latest/develop/security.html" rel="noopener noreferrer"&gt;docs.u-boot.org/en/latest/develop/security.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;wolfSSL releases and vulnerabilities: &lt;a href="https://github.com/wolfSSL/wolfssl/releases" rel="noopener noreferrer"&gt;github.com/wolfSSL/wolfssl/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BlueZ security advisories: &lt;a href="https://github.com/bluez/bluez/security/advisories" rel="noopener noreferrer"&gt;github.com/bluez/bluez/security/advisories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GStreamer security center: &lt;a href="https://gstreamer.freedesktop.org/security/" rel="noopener noreferrer"&gt;gstreamer.freedesktop.org/security&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;WebKitGTK security advisories: &lt;a href="https://webkitgtk.org/security/WSA-2026-0006.html" rel="noopener noreferrer"&gt;WSA-2026-0006&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;containerd security advisories: &lt;a href="https://github.com/containerd/containerd/security/advisories" rel="noopener noreferrer"&gt;github.com/containerd/containerd/security/advisories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CISA Known Exploited Vulnerabilities catalog: &lt;a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog" rel="noopener noreferrer"&gt;cisa.gov/known-exploited-vulnerabilities-catalog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Debian security tracker: &lt;a href="https://security-tracker.debian.org/tracker/source-package/bluez" rel="noopener noreferrer"&gt;BlueZ&lt;/a&gt;, &lt;a href="https://security-tracker.debian.org/tracker/source-package/u-boot" rel="noopener noreferrer"&gt;U-Boot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Advisories without a CVE: &lt;a href="https://gstreamer.freedesktop.org/security/sa-2026-0081.html" rel="noopener noreferrer"&gt;GStreamer-SA-2026-0081&lt;/a&gt;, &lt;a href="https://gstreamer.freedesktop.org/security/sa-2026-0080.html" rel="noopener noreferrer"&gt;GStreamer-SA-2026-0080&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Kernel &amp; Embedded News: slab_tiny Targets 7.4; inotify Side Channel</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Tue, 29 Sep 2026 04:09:39 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-slabtiny-targets-74-inotify-side-channel-8l0</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-slabtiny-targets-74-inotify-side-channel-8l0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Linux 7.4 is set to gain a slab_tiny boot option that replaces the compile-time CONFIG_SLUB_TINY, letting one kernel image serve both small-memory and full-size boards, alongside a sheaves refill patch worth 24% on an mmap microbenchmark. Security researchers demonstrated that inotify leaks keystroke timing and authentication-prompt timing; the kernel's partial fix is already in the longterm series. Linux 7.3 reached rc5 with a final release projected for mid-October, and the 7.1 series is now end-of-life. RK3588 mainline video decoding is moving towards dual-core operation, and the kernel may gain an AGENTS.md file for AI coding agents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This edition has a common direction: decisions are moving to where they can still be changed. The memory allocator's small-system mode is moving from build time to boot time, a security fix closes an interface that reported more than anyone intended, and the development process is being adjusted for the tools that now submit and review patches. For embedded teams, three of the five items feed directly into base-kernel planning for the next twelve months.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this edition
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A slab_tiny boot option is queued for 7.4&lt;/strong&gt; — CONFIG_SLUB_TINY is set to be replaced by a runtime parameter, and a small sheaves patch delivers a 24% microbenchmark gain. &lt;em&gt;— planning signal&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inotify shown to leak keystroke and authentication timing&lt;/strong&gt; — watch permission on a directory is enough; the partial kernel fix already sits in the longterm series. &lt;em&gt;— check your device&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;7.3 at rc5, final projected for 18 October; 7.1 is end-of-life&lt;/strong&gt; — large but unalarming release candidates, and a base-kernel decision for anyone still on 7.1. &lt;em&gt;— plan your base kernel&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RK3588 mainline video decoding: merged codecs and the dual-core road&lt;/strong&gt; — H.264 and HEVC decode has been upstream since 7.0; the second decoder core is the next step. &lt;em&gt;— long-term watch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AGENTS.md proposed for the kernel tree&lt;/strong&gt; — a file to point AI coding agents at the kernel's own rules, and a disagreement about how much they should read. &lt;em&gt;— process watch&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The slab_tiny boot option: small-system allocator mode moves to run time
&lt;/h2&gt;

&lt;p&gt;Vlastimil Babka, the slab maintainer, posted an eight-patch series on 23 September that replaces CONFIG_SLUB_TINY with a slab_tiny boot option. The compile-time Kconfig switch is deprecated; the same kernel binary decides at boot whether to run the allocator in its minimal-footprint mode. The series also converts slab_debug handling and is aimed at the 7.4 merge window.&lt;/p&gt;

&lt;p&gt;CONFIG_SLUB_TINY arrived in Linux 6.2 as part of deprecating the old SLOB allocator, which was removed soon after. It trades allocation throughput for lower memory overhead, which is why it appears in defconfigs for boards in the tens-of-megabytes class. The cost until now has been a separate kernel build: a distribution or BSP that wanted the tiny behaviour had to ship a second image.&lt;/p&gt;

&lt;p&gt;That cost is what the change removes. One image can boot with slab_tiny on a 64 MB industrial controller and without it on a 4 GB module, and the choice can be tested by editing the kernel command line instead of rebuilding. The same week brought a performance patch at the other end of the allocator: Hao Li's 81-line change lets prefilled sheaves — the per-CPU object caches SLUB gained recently — refill directly from the "barn", the shared store of full sheaves, instead of always going back to partial slabs. On the will-it-scale mmap1 test the patch raises throughput 24.2%, from 27.8 to 34.5 million operations, and cuts failed barn returns by 44%. It carries Reviewed-by tags from Harry Yoo and from Babka and is queued in the slab tree for 7.4.&lt;/p&gt;

&lt;p&gt;Taken together the direction is clear: with the slab_tiny boot option at one end and sheaves tuning at the other, the allocator is becoming one code base whose behaviour is chosen and tuned at run time, from very small systems to very parallel ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for BSP maintainers
&lt;/h3&gt;

&lt;p&gt;If any of your defconfigs set CONFIG_SLUB_TINY=y, follow this series: once it lands, a config refresh will drop the symbol and the behaviour will need to be carried in the bootargs of your device tree or bootloader environment instead. The consolidation is an opportunity — image variants that existed only for the allocator choice can be merged. Before enabling the slab_tiny boot option on existing products, measure with your own workload; the tiny mode's throughput cost is real and always has been, and it is now cheap to A/B test because no rebuild is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  inotify is a side channel: keystroke timing with no read access
&lt;/h2&gt;

&lt;p&gt;Researchers at Graz University of Technology, in a team including Sudheendra Raghav Neela and Daniel Gruss, have shown that file-notification interfaces on all major operating systems can be used to reconstruct user behaviour. The paper is accepted at ACM CCS 2026 in November. &lt;strong&gt;The core finding is that watch permission on a directory is sufficient — no read access to any file's contents is required — to observe when other users type, browse or authenticate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On Linux the attacks use inotify. Watching device nodes under /dev/input yields inter-keystroke timing. A second demonstration targets KDE Plasma: watching /usr/bin/pkexec reveals the moment Polkit spawns an authentication dialog, precisely enough to overlay a fake password prompt. The same class of attack works through Android's FileObserver, where message-arrival activity in application folders becomes visible, and through the Windows and macOS equivalents; on Windows, the researchers fingerprinted browsing across the top thousand websites with an F1 score of 97.8%.&lt;/p&gt;

&lt;p&gt;The kernel side is partly fixed. The commit "fsnotify: do not generate ACCESS/MODIFY events on child for special files" stops parent-directory watchers from receiving access and modify events for character devices and other special files, closing the /dev/input path. It is tracked as CVE-2025-68788; the kernel CVE announcement of 13 January lists the fix in mainline 6.19-rc2 and in 6.1.160, 6.6.120, 6.12.64 and 6.18.3, and the researchers additionally list 5.15.198 and 5.10.248 for the older longterm series. The mitigation is partial by design: notification timing on regular files is the interface working as specified, so the broader channel remains.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to check your device
&lt;/h3&gt;

&lt;p&gt;The exposure matters wherever untrusted code shares a kernel with users: multi-user systems, kiosks, and containers on shared embedded hosts. Compare your running kernel against the fix versions for its series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 6.12 kernel needs 6.12.64 or later; 6.6 needs 6.6.120; 6.1 needs 6.1.160; 6.18 needs 6.18.3. Vendor BSP kernels that stopped taking stable updates will not have the fix regardless of series. To see which processes on a device hold inotify watches at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;find /proc/[0-9]&lt;span class="k"&gt;*&lt;/span&gt;/fdinfo &lt;span class="nt"&gt;-type&lt;/span&gt; f 2&amp;gt;/dev/null | xargs &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; inotify 2&amp;gt;/dev/null | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;/ &lt;span class="nt"&gt;-f3&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is a list of PIDs. On a locked-down device that list should be short and explainable; anything unexpected watching /dev or system binaries deserves a closer look.&lt;/p&gt;

&lt;h2&gt;
  
  
  7.3 at rc5 and on schedule; the 7.1 series is finished
&lt;/h2&gt;

&lt;p&gt;Linux 7.3-rc5 was released on 27 September with 577 commits. The release candidates this cycle have been consistently large, and rc5's shape was unusual — drivers under a third of the diff, selftests around a quarter — but Linus Torvalds called the content routine and said nothing looks alarming. The fixes concentrate in KVM and perf, the scheduler and BPF, networking drivers and DRM, and HID++ support for the Logitech Bolt receiver was reverted after problems.&lt;/p&gt;

&lt;p&gt;If the usual seven release candidates hold, 7.3 ships on 18 October; an eighth would push it to 25 October. Those dates are projections from the cadence, not announcements. The 7.4 merge window opens immediately after the release, which is when the slab work above, the parallelised kernel build series and the other queued 7.4 material would land.&lt;/p&gt;

&lt;p&gt;The same week closed a chapter: with 7.1.13, the 7.1 series is end-of-life on kernel.org. The 25 September stable updates were 7.2.8 and 6.18.54, and the longterm lines 6.12, 6.6, 6.1, 5.15 and 5.10 all saw releases earlier in the month. A product tracking 7.1 now has no upstream security path.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for release planning
&lt;/h3&gt;

&lt;p&gt;Teams on a 7.1-based kernel should treat the move as due now, not at the next convenient milestone: 7.2 is the short-lived option, and 6.18 or 6.12 are the longterm ones. Teams planning new platforms around 7.3 can start validation against rc5, since late rcs rarely change interfaces. And anything you intend to land upstream in 7.4 needs to be in a maintainer tree in the next three weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  RK3588 video decoding in mainline: what is merged and what the second core needs
&lt;/h2&gt;

&lt;p&gt;At Kernel Recipes in Paris on 21–23 September, Detlev Casanova of Collabora presented the state of upstream video decoding for Rockchip's RK3588 and RK3576.&lt;/p&gt;

&lt;p&gt;The foundation is already in place. Linux 7.0 merged H.264 and HEVC decoding for the RK3588's VDPU381 and the RK3576's VDPU383 as part of the rkvdec driver, implementing the V4L2 stateless decode API. The 17-patch series brought new UAPI controls for HEVC reference-picture-set handling and solved an awkward platform problem — the decoder resets its embedded IOMMU, which the IOMMU framework had to learn to recover from. GStreamer 1.28 and FFmpeg already consume the stateless API, so the merged support is usable from ordinary media pipelines.&lt;/p&gt;

&lt;p&gt;The talk's subject is the next step. The RK3588 carries two VDPU381 cores, and multi-core scheduling is not yet enabled upstream, so mainline currently decodes on one core. VP9 support exists in preliminary form, AV1 on the RK3576 is earlier still, and the older VDPU346 on RK356x parts is a separate effort. Dual-core operation is what would bring mainline decode throughput to parity with the vendor stack on high-bitrate 4K content.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to evaluate it
&lt;/h3&gt;

&lt;p&gt;If your RK3588 product carries the vendor 6.1 BSP mainly for video, re-test your actual codec mix on a 7.x kernel: H.264 and HEVC pipelines through GStreamer are the supported path today, while VP9 or AV1 content still requires the vendor stack. Measure single-core decode against your worst-case streams before deciding whether you must wait for multi-core support. A product that passes on one core can plan its mainline migration now and treat the second core as future headroom rather than a blocker.&lt;/p&gt;

&lt;h2&gt;
  
  
  AGENTS.md: telling AI agents where the kernel's rules are
&lt;/h2&gt;

&lt;p&gt;Sasha Levin posted a patch on 24 September adding an AGENTS.md file to the kernel tree — the convention several AI coding tools read on startup — pointing agents at the kernel's README and the existing submission documentation rather than duplicating any of it. His stated motivation is practical: in testing without the file, agents mis-attributed their work, one adding a Signed-off-by tag it had no right to and another inventing an attribution tag instead of using the kernel's Assisted-by convention; with the file present, the same agents followed the rules.&lt;/p&gt;

&lt;p&gt;The objections on the list are practical too. Making every agent ingest the full documentation on every run costs context and tokens, and several developers argued for a smaller, purpose-written file for machine consumption instead. The discussion is unresolved, and it continues this year's run of process adaptations for automated contributors.&lt;/p&gt;

&lt;p&gt;The substance here is not the file itself but what it acknowledges: patch submission norms are now written for tools as well as people, and the kernel is choosing to steer the tools rather than pretend they are not present.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it
&lt;/h3&gt;

&lt;p&gt;The pattern transfers directly to private trees. If your team runs AI assistants against a BSP or internal kernel fork, add a repository-level agent instruction file that points at your own contribution rules — coding style, commit-message format, sign-off policy, and which subsystems are off-limits. Enforce the attribution convention in review regardless of tooling: the kernel's Assisted-by practice is a reasonable template to copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://patchwork.kernel.org/series/1172379/" rel="noopener noreferrer"&gt;slab: replace CONFIG_SLUB_TINY with a slab_tiny boot parameter (patch series)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-Slab-Tiny-Boot-Option" rel="noopener noreferrer"&gt;"slab_tiny" boot option proposed for tiny Linux systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/linux-mm/linux-mm/pull/4889" rel="noopener noreferrer"&gt;mm/slub: refill prefilled sheaves from the barn (list mirror)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-7.4-Refill-Sheaves-Barn" rel="noopener noreferrer"&gt;MM change slated for Linux 7.4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://inoti.fyi/" rel="noopener noreferrer"&gt;File Notification Attacks (research site)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1096431/" rel="noopener noreferrer"&gt;Research into file-notification attacks on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ratatoskr.run/linux-cve-announce/2026/01/8047582" rel="noopener noreferrer"&gt;CVE-2025-68788 announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/" rel="noopener noreferrer"&gt;kernel.org releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-7.3-rc5-Released" rel="noopener noreferrer"&gt;Linux 7.3-rc5 released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ostechnix.com/linux-kernel-7-3-rc5-released/" rel="noopener noreferrer"&gt;Linux 7.3-rc5 details&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.collabora.com/news-and-blog/news-and-events/rk3588-and-rk3576-video-decoders-support-merged-in-the-upstream-linux-kernel.html" rel="noopener noreferrer"&gt;RK3588 and RK3576 video decoders merged upstream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.collabora.com/news-and-blog/news-and-events/decoding-with-rockchip-at-kernel-recipes-2026.html" rel="noopener noreferrer"&gt;Decoding with Rockchip at Kernel Recipes 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cnx-software.com/2026/02/27/rockchip-rk3588-rk3576-h-264-and-h-265-video-decoders-mainline-linux/" rel="noopener noreferrer"&gt;RK3588/RK3576 decoders in mainline Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-Considers-AGENTS-MD" rel="noopener noreferrer"&gt;Linux kernel developers consider adding AGENTS.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This digest is from &lt;a href="https://www.techveda.live/" rel="noopener noreferrer"&gt;TECH VEDA&lt;/a&gt;, where we run live, instructor-led training on the Linux kernel and embedded Linux.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>security</category>
    </item>
    <item>
      <title>The Danger of Cargo-Cult Engineering: Why a Correct Fix Can Break Your System</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Fri, 25 Sep 2026 05:37:35 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/the-danger-of-cargo-cult-engineering-why-a-correct-fix-can-break-your-system-pl5</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/the-danger-of-cargo-cult-engineering-why-a-correct-fix-can-break-your-system-pl5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Cargo-cult engineering is keeping the visible form of a fix, a configuration or a process without the condition that made it work where it came from. It happens with code copied from a forum and with code an AI assistant generated. The protection is a habit: before you keep any line, name the condition it depends on and check whether that condition exists in your system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are bringing up a sensor on a new board. The vendor's evaluation board already has a device tree node for the same sensor (the description that tells the Linux kernel what hardware is on the board), so you copy it, change the I2C address, and boot. The driver fails to probe. The chip-ID read gets no response on the bus.&lt;/p&gt;

&lt;p&gt;Two days later, a scope on the reset pin shows it held low. The copied node described the reset line as active-low. On the evaluation board it is. On your board, the hardware team added an inverter on that line, so the sensor was held in reset the whole time.&lt;/p&gt;

&lt;p&gt;The node was not wrong. It was correct for a board you do not have. The same thing happens with a retry copied from a forum answer, a flag taken from another team's repository, or a fix an AI assistant suggested.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is cargo-cult engineering?
&lt;/h2&gt;

&lt;p&gt;The term comes from Caltech's 1974 commencement address by the physicist Richard Feynman, published that June as "Cargo Cult Science". He used it for work that copies every visible step of a method but leaves out the part that made the method work. He described it this way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"They're doing everything right. The form is perfect. It looks exactly the way it looked before. But it doesn't work."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feynman based the name on a simplified account of Melanesian movements, and &lt;a href="https://www.anthroencyclopedia.com/entry/cargo-cults" rel="noopener noreferrer"&gt;most anthropologists now reject the label as misleading&lt;/a&gt;. Engineers use it, often as "cargo cult programming", for one narrow idea: the form of a practice has been copied, and its condition has not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every line depends on a condition
&lt;/h2&gt;

&lt;p&gt;Almost every line in a working system is there because of some condition. The reset polarity matches the way the board is wired. A delay allows for how long a supply takes to become stable. A retry allows for a service that is slow to start.&lt;/p&gt;

&lt;p&gt;When you copy the line, the condition does not come with it. Nothing in the text of &lt;code&gt;GPIO_ACTIVE_LOW&lt;/code&gt; tells you it depended on the absence of an inverter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It worked there" is evidence about there. It tells you nothing about here until you have checked the condition.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is different from not understanding the code. You may know exactly what &lt;code&gt;msleep(100)&lt;/code&gt;, a &lt;code&gt;volatile&lt;/code&gt; qualifier or a retry loop does. The harder question is whether the condition each of them depends on exists in your system at all. Only the first kind of knowledge is carried by the copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples of cargo-cult code in embedded and Linux projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Yocto &lt;code&gt;bbappend&lt;/code&gt; (a file that changes someone else's build recipe) from a forum, adding &lt;code&gt;INSANE_SKIP&lt;/code&gt; to switch off a build-time quality check. The warning was harmless for the person who posted it. In your build it may be reporting a real problem, and now nothing reports it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;volatile&lt;/code&gt; used to make a shared variable safe across CPUs. The kernel's own documentation says &lt;a href="https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html" rel="noopener noreferrer"&gt;its use in kernel code "is almost never correct"&lt;/a&gt;. It only stops the compiler from optimising the accesses. It does not make updates atomic or ordered between CPUs, which is the condition people copy it for. That needs locks or atomic operations.&lt;/li&gt;
&lt;li&gt;A device tree node an AI assistant generated for a closely related SoC. The pin and clock names compile on your part, but they select the wrong pads.&lt;/li&gt;
&lt;li&gt;A retry loop copied into a test script. In the original repository, a service was slow to start. In yours, the retry hides a race in the code under test that fails one run in three.&lt;/li&gt;
&lt;li&gt;Tests an assistant generated from the code rather than from the requirement. They pass because they check what the code does today, including its bugs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why cargo-cult fixes spread
&lt;/h2&gt;

&lt;p&gt;A copied form usually appears to work on the day it is added, so it stays. Then it gets copied again.&lt;/p&gt;

&lt;p&gt;The next engineer copies it from your driver, not from the original situation. "It is in three drivers already" then sounds like a reason, but all three copies come from one condition on one board, checked once at most.&lt;/p&gt;

&lt;p&gt;AI assistants can make this worse. An assistant has seen the most common form of a pattern many times, often from older vendor code. It has seen the condition far less often, because the condition was usually never written down. Ask an agent to fix a flaky test and it will often add a retry, a sleep or a longer timeout.&lt;/p&gt;

&lt;p&gt;Ask it why the line is needed, and it will give you a reasonable-sounding condition. It may also write that condition into a comment or commit message, where the next engineer will trust it more than a bare line.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An assistant's explanation of why a line is needed is a claim to check, not a check.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to check whether a line is cargo-cult code
&lt;/h2&gt;

&lt;p&gt;For anything you copied, generated with an assistant, or found in a codebase and cannot explain, ask two questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What condition does this depend on?&lt;/strong&gt; Name it in one sentence: "the rail takes 80 ms to become stable", "the reset line is active-low on this board". If you cannot name it, that is your first finding. With generated code, you can ask the assistant to state the condition for each non-obvious line, as a list of claims to verify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does that condition exist here?&lt;/strong&gt; Check it against something real: the schematic, the datasheet, the timing on your board, the log from your build. Not against the source you copied from, or the assistant's explanation of it.&lt;/p&gt;

&lt;p&gt;For code already in the tree, start with its history. Run &lt;code&gt;git blame&lt;/code&gt; or &lt;code&gt;git log -S&lt;/code&gt; and read the commit that added the line. The condition is often recorded there. If it is not, use a removal test: on a branch, before you delete the line, write down what you expect to break. Then remove it and test. If you could not predict anything, you do not yet know its condition.&lt;/p&gt;

&lt;p&gt;If nothing breaks, do not delete it yet. Your tests may simply not cover the condition, such as a colder board or an older silicon revision. Keep the line, write down the condition you suspect, mark it unverified, and ask whoever owns that code. For power sequencing, reset timing or anything safety-related, read the datasheet first. Removing a line to see what happens can damage hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to stop your code becoming someone else's cargo cult
&lt;/h2&gt;

&lt;p&gt;A few years into your career, other engineers copy your driver, recipe or build script exactly as you left it.&lt;/p&gt;

&lt;p&gt;So write the condition next to the form. A comment that says &lt;code&gt;/* ACTIVE_HIGH: rev B adds an inverter on RESET_N */&lt;/code&gt; is worth more than one that says &lt;code&gt;/* active low */&lt;/code&gt;, because the first tells the next engineer when the line no longer applies. State only conditions you have checked, including in comments and commit messages an assistant drafted for you. How to write those commit messages is the subject of &lt;a href="https://www.techveda.live/2026/09/03/epistemic-debt-ai-generated-code/" rel="noopener noreferrer"&gt;The Code Is Yours. The Understanding Is Not.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you review other people's changes, make one request: for any delay, retry, skipped check or unusual flag, the pull request description should name the condition it depends on and say how it was checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try this on your own codebase
&lt;/h2&gt;

&lt;p&gt;Pick three lines in your project that nobody on the team can explain: a delay, a flag, a compiler option, a skipped check. For each, read its history, write the condition you think it depends on and what you expect to break without it. Then test one on a branch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before you keep any line, copied or generated, name the condition it depends on and check that condition here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Copying is not the problem, and neither is using an assistant. Good examples save real time. The danger is keeping the fix and assuming the condition was the same.&lt;/p&gt;

&lt;p&gt;This is one reason TECH VEDA sessions are live and built around problem scenarios: when you work through a scenario with a mentor and other engineers, "why is this line here?" gets asked at the moment you would otherwise copy it.&lt;/p&gt;

&lt;p&gt;Source: Richard P. Feynman, "Cargo Cult Science", Caltech commencement address, 1974; published in Engineering and Science, June 1974.&lt;/p&gt;

&lt;p&gt;If you want to work through device tree, board bring-up and BSP problems in live, mentor-led sessions, see &lt;a href="https://www.techveda.live/embedded-linux-bsp-development/" rel="noopener noreferrer"&gt;TECH VEDA's Embedded Linux BSP Development course&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techveda.live/2026/09/25/cargo-cult-programming-copied-code/" rel="noopener noreferrer"&gt;TECH VEDA&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>career</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why a Watchdog Is Not a Reliability Strategy</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Fri, 25 Sep 2026 04:23:25 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/why-a-watchdog-is-not-a-reliability-strategy-53md</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/why-a-watchdog-is-not-a-reliability-strategy-53md</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A hardware watchdog converts an unknown failure into a reboot. That is containment, not a reliability strategy, because the reset names no fault and erases the evidence that would have named it. The minimum a shipping product needs is ordered timeouts — kernel detection thresholds set below the watchdog timeout, so the kernel gets to say what broke before the board resets — plus a persistent console region in RAM, which is the only thing that survives a reset the kernel did not perform itself. The watchdog stays; it just moves to the last rung instead of being the whole ladder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"We have a watchdog" is one of the most common answers to "what happens if the device locks up in the field", and it is not a wrong answer. It is an incomplete one. A watchdog guarantees exactly one thing: a device that stops petting it will restart. It makes no statement about why the device stopped, whether restarting helps, or whether the same thing will happen again in six hours. Treating that single guarantee as a &lt;strong&gt;reliability strategy&lt;/strong&gt; is the mistake, and it is a mistake that survives to production because the symptom it produces — a device that is usually up — looks like success.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context: what a reset actually buys
&lt;/h2&gt;

&lt;p&gt;The watchdog's value is real. It handles the failure class where software has stopped making progress and no operator is present, and it does so without requiring anyone to understand the fault first. For a remote device that is worth having.&lt;/p&gt;

&lt;p&gt;The limits are equally concrete. A reset acts on one symptom — the petting stopped — so every failure that keeps the petting loop running is invisible to it: a service producing wrong output, a sensor path that has silently degraded, a disk filling up, one of five daemons dead while the other four keep the system looking alive. A reset also destroys the machine state that would explain the fault. RAM is gone, and unless something wrote to persistent storage first, the next boot starts with no account of what happened.&lt;/p&gt;

&lt;p&gt;A third limit is easy to miss: a reset has no memory. The board that resets every six hours and the board that has reset once in a year look the same in a naive fleet view — both are up. Without reset-cause accounting, a reliability regression is indistinguishable from a healthy fleet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options for a reliability strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1 — Reset and forget
&lt;/h3&gt;

&lt;p&gt;Arm the hardware watchdog, pet it, ship. Nothing records why a reset happened.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For:&lt;/strong&gt; almost no engineering cost, no reserved RAM, no boot-time work, and it genuinely recovers the common lockup case unattended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Against:&lt;/strong&gt; every field failure arrives as "it rebooted" with no evidence attached. You cannot tell a watchdog reset from a power glitch, or two different bugs apart. Debugging then depends on reproducing the fault on a bench unit, which for timing- and load-dependent faults may never happen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option 2 — Detect, record, then reset
&lt;/h3&gt;

&lt;p&gt;Keep the watchdog, but let the kernel's own detectors run first and make sure their output survives. Linux already ships the detection half. The softlockup detector reports a CPU looping in kernel mode without yielding; its threshold is &lt;code&gt;2 * watchdog_thresh&lt;/code&gt;, and &lt;code&gt;watchdog_thresh&lt;/code&gt; defaults to 10 seconds, so that is 20 seconds. The hardlockup detector reports a CPU looping with interrupts disabled, using NMI perf events where the architecture supports them or an SMP "buddy" arrangement where it does not — worth checking on single-core parts, where neither is available. The hung task detector reports a task stuck in uninterruptible D state, controlled by &lt;code&gt;hung_task_timeout_secs&lt;/code&gt;, whose default of 120 seconds comes from &lt;code&gt;CONFIG_DEFAULT_HUNG_TASK_TIMEOUT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default these detectors log and let the system continue. &lt;code&gt;softlockup_panic&lt;/code&gt; and &lt;code&gt;hung_task_panic&lt;/code&gt; turn a detection into a panic instead, and the &lt;code&gt;kernel.panic&lt;/code&gt; sysctl decides what follows: zero loops forever, a negative value reboots immediately, a positive value reboots after that many seconds, with 60 recommended when a software watchdog is in use. &lt;code&gt;panic_on_oops&lt;/code&gt; covers the kernel hitting an oops or a BUG and otherwise continuing in an undefined state; whether it is on depends on whether the kernel was built with &lt;code&gt;CONFIG_PANIC_ON_OOPS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The recording half is pstore with a ramoops backend: a reserved region of RAM declared in the device tree with &lt;code&gt;compatible = "ramoops"&lt;/code&gt;. Two of its sub-regions matter here, and they behave differently in a way that decides what a watchdog reset leaves behind. &lt;code&gt;record-size&lt;/code&gt; backs the oops and panic records, which the kernel writes through its kmsg dump path at the moment it dies; after the next boot they appear under &lt;code&gt;/sys/fs/pstore&lt;/code&gt; as &lt;code&gt;dmesg-ramoops-N&lt;/code&gt;. &lt;code&gt;console-size&lt;/code&gt; backs a separate region that the ramoops console backend writes continuously as kernel messages are printed, and it appears as &lt;code&gt;console-ramoops-0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A hardware watchdog reset is not a panic.&lt;/strong&gt; The SoC simply restarts, so the kernel never reaches its dump path and no &lt;code&gt;dmesg-ramoops&lt;/code&gt; record is produced at all. What survives is the console region, because it had already been written message by message. That is the reason &lt;code&gt;console-size&lt;/code&gt; is not optional on a product with a hardware watchdog: without it, a watchdog reset leaves pstore empty and you are back to Option 1. The kernel documentation raises this scenario when explaining ramoops' optional software ECC — after a hardware reset triggered by a watchdog, RAM may be somewhat corrupt but is usually still restorable, which is why ECC is offered for exactly this case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For:&lt;/strong&gt; resets arrive with evidence attached — a full dmesg record where the kernel panicked, the console tail where the watchdog got there first — and the causes become distinguishable. Faults that only appear in the field become debuggable from the field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Against:&lt;/strong&gt; it costs a reserved RAM region, device tree work, and the discipline of reading pstore on every boot and shipping the contents somewhere. The panic sysctls also make the device reboot where it previously limped along — correct behaviour, and still a change your test team will notice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option 3 — Contain and degrade
&lt;/h3&gt;

&lt;p&gt;Add defined behaviour per component above Option 2: each service has a declared failure response, the product has a stated degraded mode, and a whole-device reset is the last rung rather than the first. A failed non-essential daemon is restarted and reported; a failed essential one moves the product into a safe, reduced state an operator can observe.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For:&lt;/strong&gt; most single-component failures never become device-wide outages, and the ones that do are announced rather than inferred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Against:&lt;/strong&gt; this is real design work. Somebody has to decide, per component, what "still working" means and what the product does without it — and that cannot be delegated to a timer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The decision
&lt;/h2&gt;

&lt;p&gt;Option 2 is the floor of a reliability strategy for any product that ships unattended. The cost is a reserved RAM region and some device tree work, and it converts field failures from unreproducible into diagnosable. Option 3 is warranted wherever a reboot has a real cost — an interrupted process, lost buffered data, a visible outage — and that judgement belongs to the product, not the platform team alone.&lt;/p&gt;

&lt;p&gt;Option 1 is defensible in one situation: a genuinely stateless device where a reboot is cheap, fast and invisible to the user, and where you have consciously accepted never diagnosing a recurring fault. That situation exists. It is rarer than the number of products relying on it.&lt;/p&gt;

&lt;p&gt;Whichever option you choose, one implementation detail decides whether it works. &lt;strong&gt;Order your timeouts.&lt;/strong&gt; If the hardware watchdog fires before the kernel's detectors reach their thresholds, you get the reset without the diagnosis, and Option 2 collapses back into Option 1 while looking configured. With stock values the numbers leave little room: a softlockup is reported at 20 seconds and a hung task at 120, while embedded watchdog timeouts are commonly 30 seconds or less. Read the three values on a real unit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/kernel/watchdog_thresh
&lt;span class="go"&gt;10
&lt;/span&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/kernel/hung_task_timeout_secs
&lt;span class="go"&gt;120
&lt;/span&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/class/watchdog/watchdog0/timeout
&lt;span class="go"&gt;30
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be precise about when that mismatch actually costs you something, because it is easy to overstate. A single task stuck in D state does not stop the rest of the system. If systemd or your petting daemon is still being scheduled, the watchdog keeps being fed, the board never resets, and the hung task detector reports normally at 120 seconds. The ordering only bites when the fault also reaches the petting path — the petting process blocked on the same stuck I/O, a system-wide scheduler or filesystem deadlock, or a health check that deliberately stops petting because it decided the product is unwell. Those are precisely the failures a watchdog exists to catch, which is why the ordering is worth getting right even though it does not apply to every hang. Either lower &lt;code&gt;hung_task_timeout_secs&lt;/code&gt; below the watchdog timeout or raise the watchdog timeout above it, and choose the two numbers together.&lt;/p&gt;

&lt;p&gt;Then confirm that something actually survives a reset. Mount pstore and look at what is there after a deliberately induced panic, and again after a deliberately starved watchdog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; pstore pstore /sys/fs/pstore
&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /sys/fs/pstore
&lt;span class="go"&gt;console-ramoops-0
dmesg-ramoops-0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a panic you should see both. After a watchdog reset you should see only &lt;code&gt;console-ramoops-0&lt;/code&gt; — and if you see nothing at all, the reserved region is misconfigured. You would rather learn that on the bench than after a field return.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequences
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You will find out your fleet is less reliable than you thought.&lt;/strong&gt; Reset-cause accounting usually reveals resets nobody was counting. That is the reliability strategy working, and it still arrives as bad news in a release meeting, so set the expectation before the data does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Panic-on-detection trades availability for diagnosability.&lt;/strong&gt; A device configured to panic on a soft lockup restarts where it previously recovered on its own. Usually the right trade for a product you have to support — and still a trade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reserved RAM region is permanent.&lt;/strong&gt; It comes out of the memory budget on every unit for the life of the product, and on a tightly specified board it competes with something real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evidence is only useful if it leaves the device.&lt;/strong&gt; A pstore record nobody reads is the same as no record. Someone must own the path from &lt;code&gt;/sys/fs/pstore&lt;/code&gt; to a place an engineer looks, and that is product work, not kernel work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;None of this replaces the watchdog.&lt;/strong&gt; It is tempting to say the kernel's detectors cover everything a hardware watchdog covers, and that is wrong in both directions. A kernel that has stopped scheduling is exactly what the softlockup detector is built to catch — it runs from an hrtimer, in interrupt context, and does not need the scheduler. What defeats the kernel's detectors is losing the mechanism underneath them: interrupts disabled on every CPU, no NMI and no second CPU for the buddy detector, a clock or power fault, or a detector that was never built in. The hardware timer sits outside all of that, which is why it belongs at the bottom of the ladder rather than being mistaken for the whole of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A watchdog answers one question — did progress stop — and nothing else. That is containment, not a reliability strategy.&lt;/li&gt;
&lt;li&gt;Order your timeouts: detection thresholds must sit below the hardware watchdog timeout, or the reset beats the diagnosis — in the failures where the hang also stops the petting, which are the ones the watchdog is there for.&lt;/li&gt;
&lt;li&gt;Stock values leave little room. A softlockup is reported at 20 s and a hung task at 120 s; embedded watchdog timeouts are frequently shorter than both.&lt;/li&gt;
&lt;li&gt;A watchdog reset is not a panic, so it produces no &lt;code&gt;dmesg-ramoops&lt;/code&gt; record. Set &lt;code&gt;console-size&lt;/code&gt; as well, and read &lt;code&gt;/sys/fs/pstore&lt;/code&gt; on every boot.&lt;/li&gt;
&lt;li&gt;Count reset causes. A device that is usually up and a device that is reliable are not the same measurement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Should I disable the hardware watchdog if I configure the kernel detectors?&lt;/strong&gt;&lt;br&gt;
No. The kernel's detectors do not need the scheduler — the softlockup detector runs from an hrtimer — but they do need the mechanism underneath them. Interrupts disabled on every CPU, no NMI and no second CPU for the buddy detector, or a clock fault all defeat them. The hardware timer sits outside all of that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why would the hung task detector never fire on my board?&lt;/strong&gt;&lt;br&gt;
If the hang also stops the watchdog being petted, the board resets at its timeout — often 30 seconds — long before the detector's default 120-second threshold. If petting continues, the board does not reset and the detector reports normally. Lower &lt;code&gt;hung_task_timeout_secs&lt;/code&gt; below the watchdog timeout, or raise the watchdog timeout above it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a watchdog reset leave anything readable in pstore?&lt;/strong&gt;&lt;br&gt;
Only the console region. A watchdog reset is not a panic, so the kernel never runs its kmsg dump path and no &lt;code&gt;dmesg-ramoops&lt;/code&gt; record is written. The console region is written continuously as messages are printed, so it survives. Set &lt;code&gt;console-size&lt;/code&gt;, not just &lt;code&gt;record-size&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does the kernel.panic sysctl do after a detector panics?&lt;/strong&gt;&lt;br&gt;
It decides what follows. Zero loops forever, a negative value reboots immediately, and a positive value reboots after that many seconds. The kernel documentation recommends 60 when a software watchdog is in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/admin-guide/lockup-watchdogs.html" rel="noopener noreferrer"&gt;Softlockup detector and hardlockup detector&lt;/a&gt; — thresholds, the &lt;code&gt;2 * watchdog_thresh&lt;/code&gt; relationship, and the NMI versus buddy detection modes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/admin-guide/ramoops.html" rel="noopener noreferrer"&gt;Ramoops oops/panic logger&lt;/a&gt; — the reserved region, software ECC, and the pstore file names.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/admin-guide/sysctl/kernel.html" rel="noopener noreferrer"&gt;Documentation/admin-guide/sysctl/kernel.rst&lt;/a&gt; — &lt;code&gt;watchdog_thresh&lt;/code&gt;, &lt;code&gt;hung_task_timeout_secs&lt;/code&gt;, &lt;code&gt;hung_task_panic&lt;/code&gt;, &lt;code&gt;softlockup_panic&lt;/code&gt;, &lt;code&gt;panic_on_oops&lt;/code&gt; and &lt;code&gt;panic&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/reserved-memory/ramoops.yaml" rel="noopener noreferrer"&gt;ramoops.yaml device tree binding&lt;/a&gt; — the authoritative property list for the reserved-memory node.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/admin-guide/kdump/kdump.html" rel="noopener noreferrer"&gt;Documentation/admin-guide/kdump/kdump.rst&lt;/a&gt; — the full crash dump mechanism, for products with the storage and boot budget for it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/09/25/watchdog-not-a-reliability-strategy/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>kernel</category>
      <category>reliability</category>
    </item>
    <item>
      <title>Xen, KVM, Jailhouse, QNX: Which Automotive Hypervisor Fits Which Integrity Level</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Thu, 24 Sep 2026 05:17:59 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/xen-kvm-jailhouse-qnx-which-automotive-hypervisor-fits-which-integrity-level-1k21</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/xen-kvm-jailhouse-qnx-which-automotive-hypervisor-fits-which-integrity-level-1k21</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The answer changes with the integrity level of the function you are partitioning, and no feature table shows that. At the higher integrity levels with hard timing requirements, the assessed commercial product is the low-risk choice by a clear margin. At the lower levels, decomposition with an independent monitor on Linux with KVM is a real shipping pattern with assessed products behind it. For workloads genuinely outside the safety argument, an assessed hypervisor buys evidence nobody will ask you for. And at every level, the timing interference argument on your own system-on-chip stays yours.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every automotive hypervisor comparison table has the same rows: type 1 or type 2, static or dynamic partitioning, licence, architectures supported. Those rows are easy to fill in and they decide nothing, because they are the same whichever function you are protecting. The question that decides a programme is which automotive hypervisor fits which integrity level. What a safety assessor will accept for an ASIL D function is not what they ask for at ASIL B, and neither resembles what they ask for on a workload carrying no safety requirement at all. This post works through the four options on that basis, as of 24 September 2026, and is explicit about the part none of them settles for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The strongest case for QNX Hypervisor for Safety
&lt;/h2&gt;

&lt;p&gt;The non-Linux option comes first and at its strongest, because the reasons a functional-safety engineer selects it are engineering reasons as well as procurement ones.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The evidence already exists, is finished, and has a reference number.&lt;/strong&gt; BlackBerry QNX holds a TÜV Rheinland functional-safety certificate for QNX Hypervisor for Safety, recorded in a public register an assessor can look up. The vendor's product brief states that QNX Hypervisor for Safety 8.0 is pre-certified to ISO 26262 ASIL D, IEC 61508 SIL 3 and IEC 62304 Class C, and that it includes safety artefacts. "Pre-certified" is the vendor's term for a safety element out of context: an assessment performed against assumed requirements that the integrator must then validate against the actual item.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The timing behaviour is specified, not emergent.&lt;/strong&gt; This is the reason that has nothing to do with paperwork. The product brief describes deterministic scheduling, bounded latency and strong domain separation, a hypervisor operating at EL2 so that guest transitions stay predictable, and support for both symmetric and bound multiprocessing so that virtual CPUs can be pinned to specific cores. A timing argument can be built on published, analysable behaviour. It cannot be built on measurements of a general-purpose scheduler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The division of labour is defined.&lt;/strong&gt; The supplier performed development activities against the standard and hands over a safety manual stating its assumptions of use. The integrator's remaining job is to confirm those assumptions hold in the actual item and to document where they do not. That work is bounded, and it can be planned and staffed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accountability is single-point.&lt;/strong&gt; One supplier, under contract, with a support obligation. When a defect appears during integration there is a company to raise it with rather than a mailing list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The privileged code base is small.&lt;/strong&gt; In a microkernel, drivers, filesystems and protocol stacks run in memory-protected user space, so the privileged trusted computing base is a fraction of a general-purpose kernel and a fault in a device service does not take the system with it. Less privileged code means less to analyse, fewer requirements to trace and fewer changes to re-assess over a long product life.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two things belong here rather than being left to a sceptical reader. First, a supplier's certificate is not your functional safety assessment: the assumptions of use, the development interface agreement and the confirmation measures at item level remain yours, and that work is frequently underestimated. Second, this is not a QNX-or-Linux choice. The vendor's own description has safety and non-safety operating systems, Android and Linux included, running side by side in isolated domains. The normal architecture is QNX hosting a Linux guest: you keep the Linux stack and stop resting the highest-integrity function on it.&lt;/p&gt;

&lt;p&gt;If your programme needs an automotive hypervisor under a function classified at the higher integrity levels, and the argument must close on a schedule, this is the option that most obviously works today. Nothing in the rest of this post is intended to argue otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  An automotive hypervisor comparison compares four categories of object
&lt;/h2&gt;

&lt;p&gt;The four are not four products. QNX Hypervisor for Safety is a commercial product with an assessed certificate and a safety manual. Xen is an open-source project that has organised a formal committee to produce and maintain safety artefacts. KVM is a set of modules inside the Linux kernel, so its evidence position is inseparable from the Linux baseline you choose. Jailhouse is a reference design that demonstrated a partitioning approach and whose public development has stopped.&lt;/p&gt;

&lt;p&gt;Three words are worth keeping apart. &lt;strong&gt;Certified&lt;/strong&gt; means an assessment happened and a certificate names a scope, with an assessor named. &lt;strong&gt;Certifiable&lt;/strong&gt; means a package exists to support an assessment the integrator still has to arrange. &lt;strong&gt;A safety package is available&lt;/strong&gt; means documentation and evidence exist and no assessment has been stated. Most of this market sits in the middle category, and collapsing the three is how a reader ends up believing something untrue.&lt;/p&gt;

&lt;p&gt;Two limits on this axis should be stated plainly, because it is the axis this automotive hypervisor comparison runs on. It is not the only axis, and it happens to be the one on which an open-source project can catch up by producing documents. It does not measure temporal determinism, and it does not measure the size of the trusted computing base as an architectural fact rather than an audit cost. On those, a certified microkernel does not need to catch up. Readers should weigh all three.&lt;/p&gt;

&lt;p&gt;The scope is narrower than the market. Commercial separation kernels, other commercial automotive hypervisor products and the packaged Linux offerings are outside this post: three of these four are the open-source options an embedded Linux team is most often asked about, and the fourth is the commercial position they are measured against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freedom from interference is the part no automotive hypervisor settles alone
&lt;/h2&gt;

&lt;p&gt;Before comparing evidence packages it is worth being clear about what an automotive hypervisor does and does not deliver, because this is the most common overestimate in the field.&lt;/p&gt;

&lt;p&gt;Spatial isolation — one partition cannot read or write another's memory, and a device cannot write outside its owner's memory through DMA — is enforced by hardware. Stage-2 translation and the system MMU do the work; the hypervisor configures them. This part is well understood and all four candidates use the same silicon mechanisms.&lt;/p&gt;

&lt;p&gt;Temporal isolation is the harder half and it is where designs are oversold. Two partitions pinned to dedicated cores still contend for the shared last-level cache, for DRAM banks and the memory controller, for interconnect bandwidth and for system MMU translation resources. That contention is invisible in the configuration file and can move worst-case execution time by a large factor. No automotive hypervisor in this comparison removes it by partitioning cores. It is addressed, where it is addressed at all, by cache partitioning or colouring, by memory bandwidth regulation, or by quality-of-service regulators in the silicon — and by the SoC vendor's own safety manual, which states what the part guarantees.&lt;/p&gt;

&lt;p&gt;That has a consequence for every section below. The automotive hypervisor is one input to a freedom-from-interference argument. The silicon is another, and often the decisive one. An evidence package that does not address timing interference on your specific SoC has not finished the job, whoever supplied it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Xen: a project that has organised its safety evidence
&lt;/h2&gt;

&lt;p&gt;The most consequential change in the open-source automotive hypervisor picture in the last year is dated 17 August 2026, when the Linux Foundation announced the Xen Safety Committee.&lt;/p&gt;

&lt;p&gt;The announcement describes a formal project committee whose responsibility, beyond maintaining source code, is to develop and maintain engineering artefacts supporting organisations' downstream functional safety certification. The founding contributors are AMD, EPAM and Renesas. What they contributed is the interesting part, because it is a list of what an assessor asks for: software safety requirements, architecture specifications, MISRA C coding-standard work, design failure mode and effects analysis, testing frameworks, tooling, code coverage and process documentation.&lt;/p&gt;

&lt;p&gt;Two further facts from the same announcement matter in practice. The project extended the support lifecycle for Xen releases to five years in 2026 — three of regular support, then two of security support — which matters because a vehicle programme cannot build on a component maintained for less time than its own integration phase. And a membership tier, Premier Plus, gives members votes on the committee and access to the committee-managed artefacts.&lt;/p&gt;

&lt;p&gt;That last point should be stated plainly. The source code is open. The safety artefacts are committee-managed and access to them is a membership benefit. Reading the code and obtaining the evidence package are two different transactions, and the project does not publish a price for the second on its membership page. This is the single most practical fact in this post for anyone budgeting an evaluation.&lt;/p&gt;

&lt;p&gt;The technical work is visible in a dated session. At an ELISA seminar on 13 May 2026, Ayan Kumar Halder of AMD and Matthew Weber of Boeing presented the work items upstreamed or published for Xen. They include MISRA C fixes, memory protection unit support, requirements, architecture and test specifications, and a testing programme running from fault injection and fuzzing to modified condition/decision coverage. The session also describes shrinking the code that has to be certified through fine-grained configuration options. The stated purpose is validating Xen as a safety element out of context.&lt;/p&gt;

&lt;p&gt;Note the tense. That is work aimed at validation, not a validation that has happened. The Xen Project says so itself, in wording more careful than most of what is written about it. Its safety page states that Xen source code is not itself safety certified, and that certification depends on the complete system, integration context, process, evidence, tooling, validation and safety case. The committee's artefacts, the same page says, are inputs to each organisation's own assessment and are not a complete product certification.&lt;/p&gt;

&lt;p&gt;That is the statement to rely on, because a supporting quote in the same press release refers to achieving baseline functional safety certification for Xen as a milestone already reached. The two contradict each other, and where a project's technical page and its press release disagree about certification status, the technical page is the one an assessor will read.&lt;/p&gt;

&lt;p&gt;One architectural point belongs here and is usually omitted. A conventional Xen deployment has a full Linux kernel in the control domain holding the device drivers, so the claim that Xen is a thin layer while KVM carries all of Linux is not true of the default configuration. Xen's case as an automotive hypervisor rests on dom0less boot and static resource partitioning, both of which the project lists as capabilities: guest domains start without waiting for a traditional control-domain boot path, and CPU, memory, device and interrupt ownership become platform design decisions. Without that configuration the trusted computing base argument does not hold.&lt;/p&gt;

&lt;p&gt;On adoption, the project's own membership page lists AMD, ARM, AWS, Boeing, EPAM, Ford Motor Company, Honda, Renesas, Vates and XenServer. Two carmakers and an aerospace manufacturer paying for a seat on the advisory board is a meaningful signal about where the work is aimed. It is not evidence that any of them ships Xen in a product, and this post makes no such claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  KVM: the evidence position is the kernel's
&lt;/h2&gt;

&lt;p&gt;KVM is the automotive hypervisor option most often misread, because the decisive fact about it is structural. It is a set of kernel modules running in kernel space. It does not boot ahead of Linux; it depends on the kernel for scheduling, memory management, drivers and device support.&lt;/p&gt;

&lt;p&gt;The consequence for evidence is that KVM is not a separable layer you can scope on its own. Any safety argument about it is an argument about a specific Linux baseline in a specific configuration. That route has a name and a published document. ISO/PAS 8926:2024, &lt;em&gt;Use of pre-existing software architectural elements&lt;/em&gt;, was published on 29 January 2024 and defines the classification and tailoring path for software not developed to conform with ISO 26262. Its own worked example of such an element is an operating system. An earlier post on this site sets out &lt;a href="https://www.techveda.live/2026/09/04/linux-safety-certification/" rel="noopener noreferrer"&gt;what a Linux safety certification actually covers&lt;/a&gt; and what a certificate on a Linux product does and does not bound.&lt;/p&gt;

&lt;p&gt;Two corrections to the compressed version of this argument. Saying KVM "has no evidence" is wrong: stable and longterm branch maintenance, kernel selftests, static analysis, vendor BSP verification records and the process work coming out of ELISA are all engineering evidence an assessor will look at. What does not exist is a packaged product certification for generic upstream KVM. And assessed Linux products do exist — Red Hat's In-Vehicle Operating System is certified by exida as a safety element out of context at ASIL-B, with a safety guidance document containing assumptions of use. The honest statement is not that Linux cannot be argued, but that it is argued at a different integrity level, by a different route, with more of the work falling on the integrator.&lt;/p&gt;

&lt;p&gt;A distinction worth drawing, because it is a common confusion. Android's Virtualization Framework uses protected KVM to run protected virtual machines. Google documents it as security-oriented, supported only on ARM64, with the property that a compromised host cannot read a protected machine's memory. That is a security claim, and there are no safety artefacts behind it. But it would be wrong to dismiss the architecture: moving isolation enforcement into a small component at EL2, and removing the host kernel from the trusted computing base for that property, is the most plausible future foundation for a Linux-side isolation argument. The evidence to support one does not exist today. That is a statement about the evidence, not about the mechanism.&lt;/p&gt;

&lt;p&gt;KVM's defensible role in a vehicle today is consolidation of workloads that sit outside the safety argument, on a Linux platform the team already runs and already maintains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jailhouse: no public development since January 2023
&lt;/h2&gt;

&lt;p&gt;Jailhouse, the fourth automotive hypervisor here, is described by its own repository as a Linux-based partitioning hypervisor that runs bare-metal applications or adapted operating systems beside Linux. It performs no scheduling, and it virtualises in software only those resources that a platform requires and that cannot be partitioned in hardware.&lt;/p&gt;

&lt;p&gt;The design is genuinely different from the other three, and its claim should be stated accurately. Assigning CPUs, memory and devices statically removes hypervisor scheduling as a source of interference, which is a real simplification. It does not remove temporal interference through the shared cache, the memory controller and the interconnect, which is the dominant problem in multicore mixed-criticality systems. Static core assignment narrows what you must argue about. It does not close the argument.&lt;/p&gt;

&lt;p&gt;The larger problem is the state of the project. Reading the public repository on 24 September 2026, the most recent tag is v0.12, dated 4 February 2020. The most recent commit on &lt;code&gt;master&lt;/code&gt; is dated 16 January 2023 and on &lt;code&gt;next&lt;/code&gt; 22 January 2023.&lt;/p&gt;

&lt;p&gt;Two caveats belong with that. Siemens may maintain the code internally and downstream forks exist, so an absence of public commits describes the public repository and not the world. And a static partitioner is a small piece of software that could reasonably reach a stable state. But a component in a vehicle needs a security response path and a maintenance commitment measured in fifteen years, and a repository with no public activity since January 2023 does not demonstrate one. For a programme starting now this is a design worth studying, not a supplier position you can enter into a safety plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this comparison does not settle
&lt;/h2&gt;

&lt;p&gt;Several things are deliberately left unclaimed. No OEM or Tier 1 is named as running any of these four as its automotive hypervisor in a production vehicle; membership of a project is not deployment, and deployment information in this industry is routinely under non-disclosure. The detailed scope of the QNX certificate is not analysed, only its existence and the category of evidence it represents. No performance, latency or footprint numbers appear anywhere, because published benchmarks for these four come from interested parties on hardware nobody else can reproduce.&lt;/p&gt;

&lt;p&gt;I did not read the Xen safety artefacts, because access to them is a membership benefit; what is described above is the project's own public description of their contents, and that limitation applies to any evaluation from outside the membership. The Jailhouse dates come from the public repository, and no statement is made about internal Siemens development. No ISO 26262 clause number is cited anywhere in this post, because the relevant parts are paid documents and only their published abstracts were read.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each one can hand an assessor today
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;What it supplies&lt;/th&gt;
&lt;th&gt;Who can obtain it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QNX Hypervisor for Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Assessed commercial product&lt;/td&gt;
&lt;td&gt;Certificate with a public register entry, plus a safety manual carrying assumptions of use&lt;/td&gt;
&lt;td&gt;Any customer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Xen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Project producing shared artefacts&lt;/td&gt;
&lt;td&gt;Requirements, architecture and test specifications, tests, coverage, static analysis, process documentation — described by the project as inputs, not a certification&lt;/td&gt;
&lt;td&gt;Premier Plus members&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KVM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linux kernel subsystem&lt;/td&gt;
&lt;td&gt;Whatever the chosen Linux baseline supplies, under the pre-existing software route; assessed Linux products exist at ASIL-B&lt;/td&gt;
&lt;td&gt;Anyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jailhouse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dormant reference design&lt;/td&gt;
&lt;td&gt;Source and a clear design; no demonstrated maintainer or security response path&lt;/td&gt;
&lt;td&gt;Anyone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is the table an automotive hypervisor comparison should have been. It still does not decide anything on its own, because what an assessor will accept depends on what the function is classified at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which automotive hypervisor fits which integrity level
&lt;/h2&gt;

&lt;p&gt;ISO 26262 does not offer one answer. It classifies a function from QM through the four ASILs, and the evidence demanded at each end of that range is not comparable. The published subject list of ISO 26262-9:2018 includes requirements decomposition with respect to ASIL tailoring. That is the mechanism behind the middle of this table: a requirement at one level can be decomposed across elements argued at lower levels, provided their independence is established.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function classified at&lt;/th&gt;
&lt;th&gt;Defensible choice today&lt;/th&gt;
&lt;th&gt;What you still owe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Higher ASIL, hard real-time&lt;/strong&gt; (for example a function whose timing budget is part of the safety requirement)&lt;/td&gt;
&lt;td&gt;An assessed commercial product. QNX Hypervisor for Safety is pre-certified by its vendor to ISO 26262 ASIL D and publishes deterministic scheduling and bounded latency.&lt;/td&gt;
&lt;td&gt;Validate the safety manual's assumptions of use against your item; your own DIA and confirmation measures; the timing interference argument on your SoC.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lower ASIL, with decomposition available&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Decomposition with an independent monitor, hosted on Linux with KVM, is a real shipping pattern. Assessed Linux products exist at this level: Red Hat's In-Vehicle Operating System is certified by exida as a safety element out of context at ASIL-B.&lt;/td&gt;
&lt;td&gt;Establish the independence the decomposition assumes; qualify your Linux baseline under the pre-existing software route; the same SoC timing argument.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Any level, if you will run your own assessment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Xen, using the Safety Committee artefacts. The project attaches no integrity level to itself, so the level you reach is the level you and your assessor can defend.&lt;/td&gt;
&lt;td&gt;Premier Plus membership to obtain the artefacts; your own assessor; a dom0less configuration, because the default control domain puts a full Linux kernel in the privileged path.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QM — outside the safety argument&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Whatever your team already runs and maintains. A rear-seat entertainment stack consolidated with a connectivity gateway does not need an assessed hypervisor.&lt;/td&gt;
&lt;td&gt;Confirm the partition really is outside the argument. Shared devices, update paths and resource exhaustion are the usual routes by which it is not.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Any level&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not Jailhouse. Its design is worth studying and its public repository has had no commit since January 2023.&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two questions settle most of this faster than any comparison table. Ask the supplier which product version and which configuration the certificate or the artefact set actually covers, because a certificate that does not name your build is not evidence about your build. Then ask what their safety manual assumes about the timing behaviour of your specific system-on-chip. The second question is the one that goes unanswered most often, and it is the one your assessor will return to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There is no single answer. Which automotive hypervisor fits depends on the integrity level of the function you are partitioning, and a feature table cannot show that.&lt;/li&gt;
&lt;li&gt;At the higher integrity levels with hard timing requirements, the assessed commercial product is the low-risk choice by a clear margin. At the lower levels, decomposition with an independent monitor on Linux with KVM is a real shipping pattern, and assessed Linux products exist at ASIL-B.&lt;/li&gt;
&lt;li&gt;Keep &lt;em&gt;certified&lt;/em&gt;, &lt;em&gt;certifiable&lt;/em&gt; and &lt;em&gt;a safety package is available&lt;/em&gt; apart. Most of this market sits in the middle one.&lt;/li&gt;
&lt;li&gt;Spatial isolation comes from the silicon and the hypervisor configures it. Temporal interference through shared cache, memory controller and interconnect is not solved by partitioning cores, and none of these four closes it for you.&lt;/li&gt;
&lt;li&gt;The Xen Safety Committee, announced on 17 August 2026, produces artefacts the project describes as inputs to your own assessment, not a product certification. Access is tied to Premier Plus membership. Xen's automotive case also depends on a dom0less configuration.&lt;/li&gt;
&lt;li&gt;Ask two questions of any supplier: which version and configuration the evidence covers, and what the safety manual assumes about your SoC's timing behaviour.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which automotive hypervisor should I use at ASIL D?&lt;/strong&gt;&lt;br&gt;
For a higher-integrity function with hard timing requirements, an assessed commercial product is the low-risk choice today. At the lower integrity levels, decomposition with an independent monitor hosted on Linux with KVM is a real shipping pattern, and assessed Linux products exist at ASIL-B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Xen safety certified?&lt;/strong&gt;&lt;br&gt;
No. The Xen Project states on its own safety page that Xen source code is not itself safety certified, and that the Safety Committee's artefacts are inputs to an organisation's own assessment rather than a product certification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I certify KVM on its own?&lt;/strong&gt;&lt;br&gt;
Not as a separable layer. KVM is a set of modules inside the Linux kernel and depends on it for scheduling, memory management and drivers, so any safety argument about KVM is an argument about a specific Linux baseline, taken under the pre-existing software route defined by ISO/PAS 8926:2024.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does an automotive hypervisor give me freedom from interference?&lt;/strong&gt;&lt;br&gt;
Only partly. An automotive hypervisor configures the hardware that provides spatial isolation. Temporal interference through shared cache, the memory controller and the interconnect persists even when partitions have dedicated cores, and it has to be addressed with the SoC's own mechanisms and its safety manual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Jailhouse still maintained?&lt;/strong&gt;&lt;br&gt;
Its public repository shows no commit on either the &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; branch since January 2023, and no release since v0.12 in February 2020. Siemens may maintain it internally and forks exist, but the public repository does not demonstrate an active maintenance or security response path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Primary: &lt;a href="https://www.linuxfoundation.org/press/xen-project-launches-shared-functional-initiative-for-safety-critical-systems" rel="noopener noreferrer"&gt;Xen Project Launches Shared Functional Initiative for Safety-Critical Systems&lt;/a&gt;, The Linux Foundation, 17 August 2026.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://xenproject.org/technology/safety/" rel="noopener noreferrer"&gt;Safety-Critical Systems&lt;/a&gt;, Xen Project — the project's own statement that the source code is not itself safety certified.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://xenproject.org/projects/embedded-and-automotive/" rel="noopener noreferrer"&gt;Embedded &amp;amp; Automotive&lt;/a&gt; and &lt;a href="https://xenproject.org/about/become-a-member/" rel="noopener noreferrer"&gt;Become a member&lt;/a&gt;, Xen Project — dom0less boot, static resource partitioning, and the member list.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://qnx.software/content/dam/qnx-xwalk/pdf/product-briefs/qnx-hypervisor-for-safety-8-product-brief.pdf" rel="noopener noreferrer"&gt;QNX Hypervisor for Safety 8.0 product brief&lt;/a&gt; and the &lt;a href="https://qnx.software/en/software/products-and-solutions/qnx-hypervisor-and-hypervisor-for-safety" rel="noopener noreferrer"&gt;product page&lt;/a&gt; — the pre-certification list, determinism claims and guest-OS description.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://elisa.tech/event/elisa-seminar-functional-safety-with-xen-zephyr-and-linux-for-avionics-automotive-and-industrial/" rel="noopener noreferrer"&gt;ELISA Seminar: Functional safety with Xen, Zephyr and Linux&lt;/a&gt;, Ayan Kumar Halder (AMD) and Matthew Weber (Boeing), 13 May 2026.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://www.iso.org/standard/83346.html" rel="noopener noreferrer"&gt;ISO/PAS 8926:2024&lt;/a&gt; — catalogue entry for the pre-existing software architectural element route.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://github.com/siemens/jailhouse/tags" rel="noopener noreferrer"&gt;siemens/jailhouse tags&lt;/a&gt; and &lt;a href="https://github.com/siemens/jailhouse/commits/master" rel="noopener noreferrer"&gt;commit history&lt;/a&gt;, read 24 September 2026.&lt;/li&gt;
&lt;li&gt;Primary: &lt;a href="https://source.android.com/docs/core/virtualization" rel="noopener noreferrer"&gt;Android Virtualization Framework overview&lt;/a&gt; — pKVM and the ARM64 restriction.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://xenproject.org/blog/xen-at-fosdem-real-world-conversations-about-xen-and-kvm/" rel="noopener noreferrer"&gt;Xen at FOSDEM: Real-World Conversations About Xen and KVM&lt;/a&gt;, Xen Project blog, 4 February 2026 — cited as the Xen project's own view.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techveda.live" rel="noopener noreferrer"&gt;TECH VEDA&lt;/a&gt;, where Raghu Bharadwaj writes a weekly automotive-Linux beat tracking what is actually shipping, what is actually certified, and what is neither.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TECH VEDA runs instructor-led training in Linux kernel internals, device drivers, embedded Linux and Yocto for engineering teams in India and beyond. If your team is working through mixed-criticality partitioning, BSP maintenance or a safety argument on Linux, that is the ground we teach on: &lt;a href="https://www.techveda.live" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>automotive</category>
      <category>embedded</category>
      <category>safety</category>
    </item>
    <item>
      <title>What PREEMPT_RT Changes: Sleeping Spinlocks (Part 1)</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Wed, 23 Sep 2026 05:28:50 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/what-preemptrt-changes-sleeping-spinlocks-part-1-3dhm</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/what-preemptrt-changes-sleeping-spinlocks-part-1-3dhm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;On a PREEMPT_RT kernel, &lt;code&gt;spinlock_t&lt;/code&gt; is not a spinlock. It is an rtmutex, and a task that fails to acquire one goes to sleep. The reason the rest of RT looks the way it does is that &lt;code&gt;preempt_disable()&lt;/code&gt; was quietly doing three jobs at once, and once RT stops calling it, the other two have to be done by hand. Sleeping spinlocks are where that shows up in the code: &lt;code&gt;rt_spin_lock()&lt;/code&gt; takes the lock, then calls &lt;code&gt;rcu_read_lock()&lt;/code&gt; and &lt;code&gt;migrate_disable()&lt;/code&gt; to put back what preemption disabling used to provide for free.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most explanations of PREEMPT_RT start with latency numbers. This series starts with the source, because the numbers follow from a handful of substitutions and the substitutions are more interesting than the histograms. This first part takes the central one: sleeping spinlocks, the conversion of &lt;code&gt;spinlock_t&lt;/code&gt; into something that can block.&lt;/p&gt;

&lt;h2&gt;
  
  
  What preempt_disable() was actually buying you
&lt;/h2&gt;

&lt;p&gt;On a mainline kernel, &lt;code&gt;spin_lock()&lt;/code&gt; disables preemption and then spins on an atomic variable until the lock is free. Ask why preemption is disabled and the obvious answer is deadlock avoidance: if the holder could be preempted by another task on the same CPU that wants the same lock, that task would spin forever against a holder that is not running.&lt;/p&gt;

&lt;p&gt;That is correct, and it is not the whole answer. Disabling preemption also has two side effects that a great deal of kernel code silently depends on.&lt;/p&gt;

&lt;p&gt;The first is CPU pinning. A task that cannot be preempted cannot be migrated, so any pointer it holds into per-CPU data stays valid for the whole critical section. Code that calls &lt;code&gt;this_cpu_ptr()&lt;/code&gt; inside a spinlock and expects the result to still refer to its own CPU three lines later is relying on this.&lt;/p&gt;

&lt;p&gt;The second is RCU. A non-preemptible region is, on a classic RCU configuration, implicitly an RCU read-side critical section, because a grace period cannot complete while a CPU sits in one. Code that dereferences an RCU-protected pointer under a spinlock without calling &lt;code&gt;rcu_read_lock()&lt;/code&gt; is relying on this too.&lt;/p&gt;

&lt;p&gt;The authors of the RT substitution say this in the file header, which is worth reading before any of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * PREEMPT_RT substitution for spin/rw_locks
 *
 * spinlocks and rwlocks on RT are based on rtmutexes, with a few twists to
 * resemble the non RT semantics:
 *
 * - Contrary to plain rtmutexes, spinlocks and rwlocks are state
 *   preserving. The task state is saved before blocking on the underlying
 *   rtmutex, and restored when the lock has been acquired. Regular wakeups
 *   during that time are redirected to the saved state so no wake up is
 *   missed.
 *
 * - Non RT spin/rwlocks disable preemption and eventually interrupts.
 *   Disabling preemption has the side effect of disabling migration and
 *   preventing RCU grace periods.
 *
 *   The RT substitutions explicitly disable migration and take
 *   rcu_read_lock() across the lock held section.
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the design of sleeping spinlocks in one comment. RT cannot disable preemption, because the whole point is to keep the kernel preemptible. So it must replace the mutual exclusion with something that blocks, and then re-create the two side effects explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sleeping spinlocks are invisible at the call site
&lt;/h2&gt;

&lt;p&gt;Nothing in a driver changes. There is no &lt;code&gt;#ifdef CONFIG_PREEMPT_RT&lt;/code&gt; at the usage site, because the substitution happens in the headers. &lt;code&gt;include/linux/spinlock_rt.h&lt;/code&gt; opens by refusing to be included on its own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef __LINUX_INSIDE_SPINLOCK_H
#error Do not include directly. Use spinlock.h
#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then redefines the API in terms of an rtmutex. Initialisation makes the substitution explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define __spin_lock_init(slock, name, key, percpu)
&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rt_mutex_base_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;__rt_spin_lock_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;percpu&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;spinlock_t&lt;/code&gt; under RT contains an &lt;code&gt;rt_mutex_base&lt;/code&gt;, and initialising the spinlock initialises the rtmutex inside it. The documentation states the two halves of the rule plainly: on a non-PREEMPT_RT kernel &lt;code&gt;spinlock_t&lt;/code&gt; is mapped to &lt;code&gt;raw_spinlock_t&lt;/code&gt; and has exactly the same semantics, while on a PREEMPT_RT kernel it is mapped to a separate rt_mutex-based implementation. &lt;code&gt;raw_spinlock_t&lt;/code&gt; is a strict spinning lock in all kernels, including RT ones. The split between the two types is the entire design, and it is why RT required touching so much of the tree: every lock had to be classified as one that may sleep or one that must not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What rt_spin_lock() actually does
&lt;/h2&gt;

&lt;p&gt;The implementation is short enough to read in full, and every line of it is the argument above made concrete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;rtlock_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;rt_mutex_base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rtm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockdep_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pi_blocked_on&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unlikely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rt_mutex_cmpxchg_acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rtm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="n"&gt;rtlock_slowlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rtm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;__rt_spin_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinlock_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rtlock_might_resched&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;rtlock_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;rcu_read_lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;migrate_disable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four things happen, in order. &lt;code&gt;rtlock_might_resched()&lt;/code&gt; is the debug annotation that this call may block. &lt;code&gt;rtlock_lock()&lt;/code&gt; tries a single compare-and-exchange to install the current task as owner, and falls into &lt;code&gt;rtlock_slowlock()&lt;/code&gt; only on contention — so an uncontended acquisition on RT is one atomic operation, much like the mainline fast path. Then &lt;code&gt;rcu_read_lock()&lt;/code&gt; and &lt;code&gt;migrate_disable()&lt;/code&gt; restore the two side effects that were lost.&lt;/p&gt;

&lt;p&gt;This is the part worth remembering about sleeping spinlocks. The lock itself is the least surprising piece. The interesting work is the two lines that put back what &lt;code&gt;preempt_disable()&lt;/code&gt; used to provide without anyone asking for it. Your code that dereferenced an RCU pointer under a spinlock still works on RT, not because RT is forgiving, but because &lt;code&gt;rt_spin_lock()&lt;/code&gt; called &lt;code&gt;rcu_read_lock()&lt;/code&gt; on your behalf. Your &lt;code&gt;this_cpu_ptr()&lt;/code&gt; is still valid for the same reason: the task is pinned, by migration disabling rather than by preemption disabling, so it remains preemptible while staying on its CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  The suffixes sleeping spinlocks quietly ignore
&lt;/h2&gt;

&lt;p&gt;This is where sleeping spinlocks surprise people reading RT code for the first time. Consider the interrupt-related variants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;spin_lock_irq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinlock_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rt_spin_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;#define spin_lock_irqsave(lock, flags)           \
    do {                                         \
        typecheck(unsigned long, flags);         \
        flags = 0;                               \
        spin_lock(lock);                         \
    } while (0)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;spin_lock_irq()&lt;/code&gt; does not disable interrupts. &lt;code&gt;spin_lock_irqsave()&lt;/code&gt; does not save them either; it assigns zero to your &lt;code&gt;flags&lt;/code&gt; variable and takes the lock. The matching &lt;code&gt;spin_unlock_irqrestore()&lt;/code&gt; ignores the flags argument entirely and calls &lt;code&gt;rt_spin_unlock()&lt;/code&gt;. This has to be so: an rtmutex acquisition can block, and blocking with interrupts disabled is not a thing the kernel can do.&lt;/p&gt;

&lt;p&gt;The bottom-half suffix is the exception, and it is a real one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;__always_inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;spin_lock_bh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinlock_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Investigate: Drop bh when blocking ? */&lt;/span&gt;
    &lt;span class="n"&gt;local_bh_disable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;rt_spin_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Softirq handlers really are still disabled. The comment left in the source is an honest one about an unresolved question, and it is the kind of thing you only find by reading the file.&lt;/p&gt;

&lt;p&gt;Two more of these are worth knowing. &lt;code&gt;spin_is_contended()&lt;/code&gt; is defined as &lt;code&gt;(((void)(lock), 0))&lt;/code&gt; — it always reports no contention, so any adaptive logic you have that backs off when a lock is busy quietly stops adapting. And &lt;code&gt;spin_trylock_bh()&lt;/code&gt; has to undo its own work on failure, disabling bottom halves, attempting the lock, and re-enabling them if the attempt did not succeed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call&lt;/th&gt;
&lt;th&gt;Mainline&lt;/th&gt;
&lt;th&gt;PREEMPT_RT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spin_lock()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;preempt off, spin&lt;/td&gt;
&lt;td&gt;rtmutex, may sleep, then RCU read lock and migration off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spin_lock_irq()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;interrupts off&lt;/td&gt;
&lt;td&gt;identical to &lt;code&gt;spin_lock()&lt;/code&gt;; interrupts stay on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spin_lock_irqsave()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;saves and disables interrupts&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;flags = 0&lt;/code&gt;, then &lt;code&gt;spin_lock()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spin_lock_bh()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;softirqs off&lt;/td&gt;
&lt;td&gt;softirqs genuinely off, then rtmutex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spin_is_contended()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;real answer&lt;/td&gt;
&lt;td&gt;always 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;raw_spin_lock()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;preempt off, spin&lt;/td&gt;
&lt;td&gt;unchanged: preempt off, spin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why the unlock order is what it is
&lt;/h2&gt;

&lt;p&gt;The release path looks over-specified until you read the comment attached to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__sched&lt;/span&gt; &lt;span class="nf"&gt;rt_spin_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinlock_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;spin_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dep_map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_RET_IP_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;migrate_enable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unlikely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rt_mutex_cmpxchg_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="n"&gt;rt_mutex_slowunlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;rcu_read_unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migration is re-enabled first, then the lock is released, and &lt;code&gt;rcu_read_unlock()&lt;/code&gt; is deliberately last. The source explains why with a use-after-free trace: a second task can be sitting in an RCU read-side section holding a pointer to the same object, waiting on the same lock. If &lt;code&gt;rcu_read_unlock()&lt;/code&gt; ran before the release, the grace period could end while the unlocking task is still about to touch &lt;code&gt;lock-&amp;gt;lock&lt;/code&gt;, a &lt;code&gt;kfree_rcu()&lt;/code&gt; callback could run, and the compare-and-exchange would then write into freed memory.&lt;/p&gt;

&lt;p&gt;The RCU read-side section that &lt;code&gt;rt_spin_lock()&lt;/code&gt; took as a convenience for callers turns out to also protect the lock word itself. That is the kind of constraint that only exists because sleeping spinlocks made the lock a real object with a lifetime, rather than a word you spin on.&lt;/p&gt;

&lt;h2&gt;
  
  
  How sleeping spinlocks avoid losing a wakeup
&lt;/h2&gt;

&lt;p&gt;A plain rtmutex sets the blocking task to &lt;code&gt;TASK_UNINTERRUPTIBLE&lt;/code&gt;. Sleeping spinlocks cannot do that, because the caller may already be in a carefully chosen state — a driver that has set &lt;code&gt;TASK_INTERRUPTIBLE&lt;/code&gt; and is about to sleep would find its state destroyed by taking a lock.&lt;/p&gt;

&lt;p&gt;So the RT lock path saves and restores it, using &lt;code&gt;current_save_and_set_rtlock_wait_state()&lt;/code&gt; before blocking and &lt;code&gt;current_restore_rtlock_saved_state()&lt;/code&gt; on acquisition, with a dedicated &lt;code&gt;TASK_RTLOCK_WAIT&lt;/code&gt; state and a &lt;code&gt;schedule_rtlock()&lt;/code&gt; variant. The documented sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task-&amp;gt;state = TASK_INTERRUPTIBLE
lock()
     block()
       task-&amp;gt;saved_state = task-&amp;gt;state
       task-&amp;gt;state = TASK_UNINTERRUPTIBLE
       schedule()
                                      lock wakeup
                                        task-&amp;gt;state = task-&amp;gt;saved_state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subtle case is a real wakeup arriving while the task is blocked on the lock. It cannot be delivered, because the task must stay blocked until the lock is free. Instead the wakeup writes &lt;code&gt;TASK_RUNNING&lt;/code&gt; into &lt;code&gt;saved_state&lt;/code&gt;, and the lock wakeup later restores that, so the task ends up runnable and the wakeup is not lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for code you write
&lt;/h2&gt;

&lt;p&gt;The practical rules follow from how sleeping spinlocks are built rather than being a separate list to memorise.&lt;/p&gt;

&lt;p&gt;Anything that must not sleep must use &lt;code&gt;raw_spinlock_t&lt;/code&gt;. That is low-level interrupt handling, scheduler and timer core, and places where hardware state is being touched. The documentation also permits it where a critical section is genuinely tiny, to avoid rtmutex overhead.&lt;/p&gt;

&lt;p&gt;Inside a &lt;code&gt;raw_spinlock_t&lt;/code&gt; you may not take a &lt;code&gt;spinlock_t&lt;/code&gt;, because the outer lock disabled preemption and the inner one may sleep. The nesting order is fixed: sleeping locks, then &lt;code&gt;spinlock_t&lt;/code&gt; and &lt;code&gt;rwlock_t&lt;/code&gt; and &lt;code&gt;local_lock&lt;/code&gt;, then &lt;code&gt;raw_spinlock_t&lt;/code&gt; and bit spinlocks. Lockdep enforces this on RT and non-RT kernels alike, which is the single most useful fact in this article: you can find most RT violations on a mainline kernel by building with lockdep enabled, long before you boot an RT kernel.&lt;/p&gt;

&lt;p&gt;Allocation flips in a way that surprises people. Calling &lt;code&gt;kmalloc(GFP_ATOMIC)&lt;/code&gt; under a &lt;code&gt;raw_spin_lock()&lt;/code&gt; fails on RT, because the allocator is fully preemptible and cannot be called from a truly atomic context. Calling it under an ordinary &lt;code&gt;spin_lock()&lt;/code&gt; is fine on RT, precisely because that lock no longer disables preemption.&lt;/p&gt;

&lt;p&gt;And do not pair interrupt disabling with a &lt;code&gt;spinlock_t&lt;/code&gt; by hand. Writing &lt;code&gt;local_irq_disable()&lt;/code&gt; followed by &lt;code&gt;spin_lock()&lt;/code&gt; is correct on mainline and broken on RT, because the rtmutex needs a preemptible context. Use &lt;code&gt;spin_lock_irq()&lt;/code&gt; or &lt;code&gt;spin_lock_irqsave()&lt;/code&gt;, which do the right thing in both configurations even though, as shown above, they do almost nothing on RT.&lt;/p&gt;

&lt;p&gt;One type cannot be converted at all. A bit spinlock is a single bit, and a bit is too small to hold an rtmutex, so bit spinlocks keep their spinning semantics on RT and inherit every &lt;code&gt;raw_spinlock_t&lt;/code&gt; restriction. Where that was unacceptable, the conversion had to be done with conditional code at the usage site rather than in the headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Under PREEMPT_RT, &lt;code&gt;spinlock_t&lt;/code&gt; maps to an rtmutex and may block. Sleeping spinlocks are the result; &lt;code&gt;raw_spinlock_t&lt;/code&gt; remains a true spinning lock in every configuration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;preempt_disable()&lt;/code&gt; was doing three jobs: excluding preemption, pinning the CPU, and blocking RCU grace periods. Sleeping spinlocks replace the first with a blocking lock and restore the other two by calling &lt;code&gt;rcu_read_lock()&lt;/code&gt; and &lt;code&gt;migrate_disable()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;_irq&lt;/code&gt; and &lt;code&gt;_irqsave&lt;/code&gt; suffixes do not touch the interrupt state on RT; &lt;code&gt;spin_lock_irqsave()&lt;/code&gt; assigns zero to your flags. The &lt;code&gt;_bh&lt;/code&gt; suffix still disables softirqs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spin_is_contended()&lt;/code&gt; always returns 0 on RT, so back-off logic built on it stops working.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rt_spin_unlock()&lt;/code&gt; calls &lt;code&gt;rcu_read_unlock()&lt;/code&gt; last on purpose, because that read-side section is also what keeps the lock word itself alive against a concurrent &lt;code&gt;kfree_rcu()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The nesting rule — no &lt;code&gt;spinlock_t&lt;/code&gt; inside a &lt;code&gt;raw_spinlock_t&lt;/code&gt; — is enforced by lockdep on mainline too, so most RT locking bugs are findable without an RT kernel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does my driver need changes to work with sleeping spinlocks?&lt;/strong&gt;&lt;br&gt;
Usually not. The substitution happens in the headers, so there is no conditional code at the call site and &lt;code&gt;spin_lock()&lt;/code&gt; keeps its name and signature. What needs review is any place you nested a &lt;code&gt;spinlock_t&lt;/code&gt; inside a &lt;code&gt;raw_spinlock_t&lt;/code&gt;, disabled interrupts by hand around a lock, or relied on &lt;code&gt;spin_is_contended()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If spinlock_t can sleep, why is an uncontended lock still fast?&lt;/strong&gt;&lt;br&gt;
Because the fast path is a single compare-and-exchange. &lt;code&gt;rtlock_lock()&lt;/code&gt; attempts &lt;code&gt;rt_mutex_cmpxchg_acquire()&lt;/code&gt; to install the current task as owner and only calls &lt;code&gt;rtlock_slowlock()&lt;/code&gt; when that fails, so an uncontended acquisition does not schedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does spin_lock_irqsave() still exist on RT if it does nothing?&lt;/strong&gt;&lt;br&gt;
So that one source file compiles and behaves correctly in both configurations. On mainline it saves and disables interrupts; on RT it sets your flags variable to zero and takes the rtmutex. Writing &lt;code&gt;local_irq_disable()&lt;/code&gt; and &lt;code&gt;spin_lock()&lt;/code&gt; separately is what breaks, because the rtmutex needs a preemptible context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I call kmalloc() while holding a lock on an RT kernel?&lt;/strong&gt;&lt;br&gt;
Under an ordinary &lt;code&gt;spin_lock()&lt;/code&gt;, yes, because that lock no longer disables preemption. Under &lt;code&gt;raw_spin_lock()&lt;/code&gt;, no, not even with &lt;code&gt;GFP_ATOMIC&lt;/code&gt;, because the allocator is fully preemptible and cannot run in a truly atomic context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I find RT locking violations without an RT kernel?&lt;/strong&gt;&lt;br&gt;
Build with lockdep enabled. The nesting constraints between sleeping locks, &lt;code&gt;spinlock_t&lt;/code&gt; and &lt;code&gt;raw_spinlock_t&lt;/code&gt; are checked on PREEMPT_RT and non-PREEMPT_RT kernels alike, so a mainline kernel with lockdep will report most of these before you ever boot RT.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next in this series
&lt;/h2&gt;

&lt;p&gt;Sleeping spinlocks rest on the rtmutex, so Part 2 takes that: how priority inheritance works, what the chain walk does when a boosted task is itself blocked, and why a counting semaphore cannot be given the same treatment. Later parts cover forced interrupt threading, &lt;code&gt;local_lock&lt;/code&gt; and &lt;code&gt;migrate_disable()&lt;/code&gt;, softirqs and RCU under RT, and the timer and console changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/locking/locktypes.html" rel="noopener noreferrer"&gt;Lock types and their rules&lt;/a&gt; — the kernel's own description of the three lock categories, the PREEMPT_RT caveats and the nesting order.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/locking/spinlock_rt.c" rel="noopener noreferrer"&gt;kernel/locking/spinlock_rt.c&lt;/a&gt; — the substitution itself, including the file header comment and the use-after-free note in &lt;code&gt;rt_spin_unlock()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/spinlock_rt.h" rel="noopener noreferrer"&gt;include/linux/spinlock_rt.h&lt;/a&gt; — the API mapping, where the suffix behaviour is visible.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.kernel.org/locking/rt-mutex-design.html" rel="noopener noreferrer"&gt;RT-mutex implementation design&lt;/a&gt; — background for Part 2.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/09/23/preempt-rt-sleeping-spinlocks/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Kernel &amp; Embedded News: Android Binder Goes Rust-Only in Linux 7.4</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Tue, 22 Sep 2026 05:47:27 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-android-binder-goes-rust-only-in-linux-74-33h2</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-android-binder-goes-rust-only-in-linux-74-33h2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Android's Binder driver is set to lose its C implementation in Linux 7.4, leaving the Rust implementation as the only one — the first time Rust replaces a deployed C driver in the mainline kernel instead of being added beside one. Two large RFCs from Google engineers question old assumptions: io_uring workers that exchange thread identities to avoid worker-thread overhead, and virtual machines that keep executing while the host kernel reboots. Amlogic announced the first Cortex-A320 SoCs for low-power edge AI, and Ubuntu 26.10 completes its move to Rust coreutils.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This edition is about replacement. Two items replace long-lived C code with Rust, one at the kernel level and one in userland; two more propose replacing settled assumptions about what a thread is and what a host reboot means. The fifth brings Armv9 down into a class of silicon that has run Armv8 little cores for a decade.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this edition
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Android Binder drops its C implementation in 7.4.&lt;/strong&gt; The Rust driver, upstream since 6.18, becomes the only Binder — and Rust becomes a hard build requirement for Android kernels. &lt;em&gt;— planning signal&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;io_uring may swap thread identities to avoid blocking costs.&lt;/strong&gt; A 15-patch RFC lets a worker thread take over the submitting thread's identity only when an operation actually blocks. &lt;em&gt;— long-term watch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Orphaned VMs": guests keep running while the host kernel is offline.&lt;/strong&gt; A 46-patch RFC extends the Live Update Orchestrator so vCPUs keep executing across a host kexec reboot. &lt;em&gt;— architecture watch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amlogic announces the first Cortex-A320 SoCs.&lt;/strong&gt; The A123X and C305X2 pair Arm's smallest Armv9 core with an 8 TOPS Transformer-capable NPU for cameras and battery devices. &lt;em&gt;— hardware watch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu 26.10 completes the Rust coreutils transition.&lt;/strong&gt; cp, mv and rm switch to the Rust implementations, the final three commands to move. &lt;em&gt;— test now&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Android Binder drops its C implementation
&lt;/h2&gt;

&lt;p&gt;Carlos Llamas of Google has posted the patch that removes the C implementation of Binder, Android's central inter-process communication driver, from the kernel: 11,470 lines deleted across twenty files. The standard Binder configuration option is rewired to require Rust support, and the module name that vendor build systems reference now points at the Rust driver. Greg Kroah-Hartman has picked the patch up for the char-misc tree, aimed at the 7.4 merge window that opens after 7.3 releases in the second half of October.&lt;/p&gt;

&lt;p&gt;The replacement was prepared over several years. The Rust Binder driver began as a demonstration by Wedson Almeida Filho and has since been maintained by Alice Ryhl; it was upstreamed in Linux 6.18, reached full feature parity rather than a convenient subset, and measures equal to or better than the C driver in performance. It has been running on shipping Android hardware for some time. Llamas' stated reason for the removal is that fifteen years of accumulated complexity made the C driver painful to maintain, with new features hard to land without introducing vulnerabilities — a fair description of a driver that is performance-critical, reference-counted, and reachable from untrusted application code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the first time, a Rust implementation is replacing a widely deployed C driver in the mainline kernel instead of being added beside one.&lt;/strong&gt; Every Rust milestone before this was additive: a new driver, an abstraction layer, an optional alternative. Deleting the C path makes Rust a hard build dependency for any kernel that needs Binder — in practice, every Android vendor kernel, and any distribution kernel that supports Android container stacks.&lt;/p&gt;

&lt;p&gt;The patch is queued, not merged, and the 7.4 window has not opened; there has been no visible opposition on the list. Binder also had a motivated corporate owner funding its rewrite to parity for years — most subsystems have no equivalent sponsor, so this is a milestone, not yet a pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for Android and embedded teams
&lt;/h3&gt;

&lt;p&gt;Teams building Android on vendor kernels at 6.6 or 6.12 are not affected until their BSP rebases to 7.4 or later, but the direction is now set: a working Rust toolchain in the kernel build becomes as basic as a working C compiler for Android work. Check today whether your kernel CI can build with Rust enabled, and treat the ability to read Rust kernel code as a near-term skill requirement for anyone who debugs IPC on Android systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  io_uring proposes exchanging thread identities
&lt;/h2&gt;

&lt;p&gt;Jens Axboe, the io_uring maintainer, posted a 15-patch RFC on 11 September with an unusual answer to an old problem. io_uring promises not to block the submitting thread, but several operations — fdatasync, statx, some openat paths — run through kernel code that was never written to be asynchronous. Today, any such operation is handed to a worker thread up front, paying a wakeup and a context switch even when the operation would have completed without blocking at all.&lt;/p&gt;

&lt;p&gt;The RFC issues these operations inline instead, and reacts only when blocking actually happens. A new task flag tells the scheduler to notify io_uring when the submitting thread is about to sleep. At that moment an idle worker takes over the submitting thread's identity — thread ID, signal state, credentials, rseq and robust lists, scheduling attributes, register state — and returns to userspace in its place. The original thread, now carrying the worker's identity, sleeps, finishes the operation, and joins the worker pool. The cover letter's benchmarks show why it is tempting: an fsync test on tmpfs improved by roughly 700 percent, because the handoff cost is now paid only when blocking is real.&lt;/p&gt;

&lt;p&gt;The risk sits in the identity exchange itself. Nothing else in the kernel may hold a reference to either thread's task structure at the moment of the swap, so the series carries a long list of disqualifying conditions: threads under ptrace, threads using perf events, kernel-tracked futex ownership, realtime scheduling policy, core-scheduling cookies, an in-progress vfork, and more. Peter Zijlstra noted that shadow stacks — enabled on most current x86 deployments — currently disqualify the handoff too, though Axboe believes the shadow stack can move with the identity. Reception on the list is best summarised by Gabriel Krisman Bertazi's verdict: "really cool and seems like very dangerous thing".&lt;/p&gt;

&lt;h3&gt;
  
  
  How to read this if you build on io_uring
&lt;/h3&gt;

&lt;p&gt;There is nothing to adopt yet; Axboe himself frames the series as a viability question, not a merge candidate. Two details deserve attention from embedded readers. Realtime scheduling excludes the handoff by design, so PREEMPT_RT systems would keep the current worker-thread behaviour and see none of the gains. And the regressions in the RFC's own numbers appear at high queue depths on operations that always block, so the win is workload-specific.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orphaned VMs: guests that outlive the host kernel
&lt;/h2&gt;

&lt;p&gt;Pasha Tatashin of Google posted a 46-patch RFC on 20 September that pushes the Live Update Orchestrator one step further. LUO, upstream since 6.19 and built on the Kexec Handover infrastructure, preserves selected state across a kexec reboot so a host kernel can be replaced under running workloads; that base is still being completed upstream. The new proposal keeps virtual machines actually executing instructions while the host kernel is down.&lt;/p&gt;

&lt;p&gt;The mechanism is called an orphaned VM: guest vCPUs continue on physical CPUs that are shielded from the reboot, while a small privileged interpose layer named the Caretaker traps VM exits and resolves what it can locally — with no host kernel and no VMM present. The series preserves vCPU file-descriptor state across the reboot gap, protects the reserved CPUs from boot-time reset signals, and deals with timekeeping drift, stray interrupts, and guest-to-guest IPI routing during the window. It has been tried on Intel, AMD and Arm server processors; the author calls it early-stage work seeking feedback, ahead of discussion at the Linux Plumbers Conference in Prague next month.&lt;/p&gt;

&lt;p&gt;The pattern matters more than the patches. Cloud providers are systematically removing the reboot as a source of downtime, and the building blocks they are upstreaming — Kexec Handover, LUO, now the Caretaker concept — are generic kernel infrastructure, not cloud-only code.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for fleet and hypervisor designs
&lt;/h3&gt;

&lt;p&gt;Industrial and telecom edge systems have the same problem in a smaller form: a gateway running a hypervisor cannot take the guests down every time the host kernel needs a security update. Nothing here is deployable yet, and the vCPU-preservation work targets large servers first. The realistic action is to study LUO and Kexec Handover now — both are documented in the kernel tree — because kexec-based live update is becoming the upstream answer to host maintenance. Product architectures that assume a full-stack reboot for every kernel fix should be re-examined against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amlogic announces the first Cortex-A320 SoCs
&lt;/h2&gt;

&lt;p&gt;Amlogic has announced the A123X and C305X2, the first announced SoCs built on Arm's Cortex-A320 — the smallest Armv9 core, introduced by Arm in February 2025 with SVE2 vector extensions. The A123X carries four A320 cores for industrial machine vision: dashcams, robots, access control, video conferencing. The C305X2 carries two, aimed at battery devices such as solar doorbells and battery IP cameras, with always-on video and pre-roll low-power modes. Both are fabricated on a 6 nm process and pair the CPUs with Amlogic's 8 TOPS ADLA3 NPU, which accelerates Transformer operators in hardware; both also carry an ADLA2 NPU — rated at 4 TOPS on the A123X for CNN workloads, and serving the AI-ISP on the C305X2 — plus a neural audio-event engine and a low-light AI-ISP.&lt;/p&gt;

&lt;p&gt;The vendor's headline numbers: 34 percent higher SPECint2006 than the Cortex-A35 this class of chip typically used, and roughly ten times the ML throughput from SVE2. The software story is thin so far — Linux compatibility, reference designs and NN SDKs are promised, with no public datasheets or block diagrams yet. Chips are sampling now, with mass production scheduled for the fourth quarter of 2026. All details are preliminary and come from the vendor's own announcement.&lt;/p&gt;

&lt;p&gt;The significance is the class of device. Camera and doorbell SoCs have run Armv8 little cores for a decade; Armv9 in this segment brings SVE2, and with it a vector baseline that inference libraries can target instead of hand-written NEON paths. On-device Transformer support in an 8 TOPS NPU also signals where vendors expect small-model workloads to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to evaluate the first Cortex-A320 parts
&lt;/h3&gt;

&lt;p&gt;Treat these as roadmap information, not design-in candidates, until an SDK and datasheets exist. The questions that decide usability will be familiar: which kernel version the BSP ships, whether the NPU stack is usable outside the vendor's pipeline, and what the upstreaming position is — none of which the announcement answers. Teams selecting camera silicon for 2027 products should add A320-based parts to the comparison table now and press vendors on the software questions early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ubuntu 26.10 finishes the move to Rust coreutils
&lt;/h2&gt;

&lt;p&gt;Canonical has completed a transition that began with Ubuntu 25.10: as of the 26.10 development release, cp, mv and rm come from the Rust coreutils project rather than GNU coreutils. Those three commands had stayed on the GNU implementations through 25.10 and 26.04 LTS because of compatibility issues that upstream uutils has since resolved. The 26.10 draft release notes now record the transition as complete, with the beta due this month and the stable release planned for 15 October, targeting Linux 7.3 as its kernel.&lt;/p&gt;

&lt;p&gt;Taken with the Binder item, the pattern is clear: in the same month, the reference C implementation of a core Android kernel driver and the last GNU file utilities in a major distribution are both replaced by Rust implementations. Both moves rest on the same argument — memory-safe reimplementations have reached practical parity.&lt;/p&gt;

&lt;p&gt;For embedded teams the relevant surface is scripts. Two decades of shell scripts encode GNU-specific behaviour in rarely used options, exact error messages, and edge-case handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to check your images and scripts
&lt;/h3&gt;

&lt;p&gt;If your build or device images derive from Ubuntu, run your provisioning and CI scripts against a 26.10 beta image before the October release reaches your base-image pipeline. Pay attention to scripts that parse cp, mv or rm output or rely on obscure options, and to anything that assumes GNU-specific error text. Debian-based and Yocto-based images are untouched by this change, but the wider ecosystem trend is worth noting in platform decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Google-Binder-C-Goodbye" rel="noopener noreferrer"&gt;Google's Binder C driver removal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hwbusters.com/news/linux-7-4-deletes-11470-lines-of-android-binder-c-code-and-the-rust-binder-driver-takes-over/" rel="noopener noreferrer"&gt;Linux 7.4 deletes 11,470 lines of Binder C code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1094303/" rel="noopener noreferrer"&gt;Thread-identity switcheroo for io_uring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/all/20260911154148.644489-1-axboe@kernel.dk/" rel="noopener noreferrer"&gt;io_uring thread identity handoff RFC (lore)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/all/20260920193650.3373435-1-pasha.tatashin@soleen.com/" rel="noopener noreferrer"&gt;Orphaned VMs RFC (lore)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Orphaned-VMs-Linux-Patches" rel="noopener noreferrer"&gt;Orphaned VMs coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/core-api/liveupdate.html" rel="noopener noreferrer"&gt;Live Update Orchestrator kernel documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cnx-software.com/2026/09/11/amlogic-a123x-and-c305x2-arm-cortex-a320-socs-target-industrial-and-low-power-aiot-applications/" rel="noopener noreferrer"&gt;Amlogic A123X and C305X2 Cortex-A320 SoCs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.desmoinesregister.com/press-release/story/122619/amlogic-launches-a123x-c305x2-next-gen-6nm-socs-built-to-power-the-edge-ai-ecosystem/" rel="noopener noreferrer"&gt;Amlogic A123X &amp;amp; C305X2 press release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Ubuntu-Completes-Rust-Coreutils" rel="noopener noreferrer"&gt;Ubuntu 26.10 completes Rust coreutils transition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://documentation.ubuntu.com/release-notes/26.10/" rel="noopener noreferrer"&gt;Ubuntu 26.10 release notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to go deeper than the news, TECH VEDA runs live, instructor-led training on Linux kernel internals and embedded Linux — see &lt;a href="https://www.techveda.live/linux-kernel-infrastructure/" rel="noopener noreferrer"&gt;Linux Kernel Infrastructure&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>rust</category>
    </item>
    <item>
      <title>Boot Confirmation: Who Decides an Update Worked?</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sat, 19 Sep 2026 16:37:41 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/boot-confirmation-who-decides-an-update-worked-2edo</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/boot-confirmation-who-decides-an-update-worked-2edo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A successful install is not a successful update. For boot confirmation, use a bootloader boot counter to catch the failures where the system never reaches userspace, and one userspace health check that confirms the slot only after the device has shown it works and can still be updated. Run a hardware watchdog under both, so a hang produces a reset that the counter records. A boot counter alone is enough only when someone can physically reach a failed device.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An update framework reports that the installation succeeded. That means only that the image reached the inactive slot and its checksum matched — nothing about whether the device will boot it, or whether the software works. &lt;strong&gt;Boot confirmation&lt;/strong&gt; answers those two questions: the booted system reports back to the bootloader, which then stops treating the new slot as unproven. The decision is who may make that report, and on what evidence. It goes one level deeper than my post on &lt;a href="https://www.techveda.live/2026/08/08/ab-update-layout-scenarios/" rel="noopener noreferrer"&gt;choosing an A/B update layout&lt;/a&gt;, which covered where the slots go.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;The SWUpdate documentation defines a successful update as four steps: the update agent runs, the device reboots, the bootloader starts the new software, and that software runs, checks itself, and declares the transaction complete. Three of the four happen after the update agent has exited. Boot confirmation has to catch two classes of failure there, and no single component sees both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first class never reaches userspace.&lt;/strong&gt; A device tree that does not match the board, a panic in early init, an unresolvable root filesystem UUID, a hang while probing a bus. No userspace runs, so none of it can report anything. Only the bootloader can notice, and only if it counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The second class boots cleanly and is still a dead product.&lt;/strong&gt; The system reaches a login prompt, but the radio never associates, a migration fails, or the main service restarts in a loop. The bootloader cannot see this; as RAUC's documentation notes, such problems appear only at runtime, sometimes only after days and many reboots.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boot confirmation options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A — a bootloader boot counter
&lt;/h3&gt;

&lt;p&gt;U-Boot implements this as Boot Count Limit (&lt;code&gt;CONFIG_BOOTCOUNT_LIMIT&lt;/code&gt;). After a power-on reset &lt;code&gt;bootcount&lt;/code&gt; is initialised to 1, and while &lt;code&gt;upgrade_available&lt;/code&gt; is non-zero each reboot increments it by one. When &lt;code&gt;bootcount&lt;/code&gt; exceeds &lt;code&gt;bootlimit&lt;/code&gt;, U-Boot executes &lt;code&gt;altbootcmd&lt;/code&gt; instead of &lt;code&gt;bootcmd&lt;/code&gt;. Two details matter on a headless device: if &lt;code&gt;bootlimit&lt;/code&gt; is undefined the feature is disabled entirely, and if &lt;code&gt;altbootcmd&lt;/code&gt; is undefined U-Boot drops into interactive mode and stays there. Linux must then reset &lt;code&gt;bootcount&lt;/code&gt; to 0 to allow further boot cycles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fw_printenv bootcount bootlimit upgrade_available
&lt;span class="go"&gt;bootcount=1
bootlimit=3
upgrade_available=1
&lt;/span&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fw_setenv upgrade_available 0
&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fw_setenv bootcount 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RAUC's U-Boot backend layers its own variables on this, &lt;code&gt;BOOT_ORDER&lt;/code&gt; and &lt;code&gt;BOOT_&amp;lt;bootname&amp;gt;_LEFT&lt;/code&gt;, driven by a boot script. Barebox instead provides a maintained framework, &lt;em&gt;bootchooser&lt;/em&gt;, keeping &lt;code&gt;remaining_attempts&lt;/code&gt; and &lt;code&gt;priority&lt;/code&gt; per target in an atomic, redundant backend — which is why RAUC's documentation recommends it.&lt;/p&gt;

&lt;p&gt;A counter is small, runs before your code, and does not depend on the application. But it counts boots, not correctness: a device that boots with a dead application passes. The state must also be written atomically — on U-Boot, a redundant environment (&lt;code&gt;CONFIG_SYS_REDUNDAND_ENVIRONMENT&lt;/code&gt;, spelled that way upstream) outside the bootloader partition — or a power cut mid-write leaves the device unable to decide anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B — a userspace health check
&lt;/h3&gt;

&lt;p&gt;Here the running system decides. RAUC provides &lt;code&gt;rauc status mark-good&lt;/code&gt; and &lt;code&gt;mark-bad&lt;/code&gt;, which reach the bootloader through its bootloader interface. The documentation suggests running mark-good from a systemd unit ordered after the services that actually matter, not at the end of boot.&lt;/p&gt;

&lt;p&gt;SWUpdate expresses the same idea through a persistent variable, &lt;code&gt;ustate&lt;/code&gt;. It is set to 1 (INSTALLED) after an update, meaning the new software is under test; the bootloader initiates a fallback and sets it to 3 (FAILED) if that software is not running; userspace resets it to 0 once confirmed. The documentation is explicit that resetting it is project specific, and can be the last action after the application has checked itself.&lt;/p&gt;

&lt;p&gt;This is the only mechanism that can judge whether the &lt;em&gt;product&lt;/em&gt; works, and you choose the evidence. But it reports nothing if it never runs, so alone it leaves the first failure class uncovered. Too permissive, it confirms broken builds; too strict, it rolls back a healthy device. The SWUpdate best-practice guide warns of a deeper risk: tying the check to your application makes the application a dependency of updatability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option C — both, over a hardware watchdog
&lt;/h3&gt;

&lt;p&gt;A counter only increments if the device reboots, and a system that hangs does not reboot. A hardware watchdog converts a hang into a reset. RAUC states this directly: the system should use a hardware watchdog during boot, and the bootloader should treat watchdog resets as failed boots.&lt;/p&gt;

&lt;p&gt;On Linux the watchdog starts when &lt;code&gt;/dev/watchdog&lt;/code&gt; is opened, then must be pinged by a write or by &lt;code&gt;WDIOC_KEEPALIVE&lt;/code&gt;. If a process closes the device without first writing the magic character &lt;code&gt;V&lt;/code&gt;, a Magic Close driver keeps it running; &lt;code&gt;CONFIG_WATCHDOG_NOWAYOUT&lt;/code&gt; removes the ability to stop it at all. Under systemd, &lt;code&gt;RuntimeWatchdogSec=&lt;/code&gt; programs it and systemd contacts it at least once every half of that interval — but it defaults to 0, meaning off. For coverage before Linux starts, U-Boot has &lt;code&gt;CONFIG_WATCHDOG_AUTOSTART&lt;/code&gt; (on by default, except ARCH_SUNXI, ARCH_STM32MP and ARCH_SNAPDRAGON), and barebox uses &lt;code&gt;boot.watchdog_timeout&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision
&lt;/h2&gt;

&lt;p&gt;For a connected product you cannot physically reach, use all three layers with different jobs. The watchdog detects that progress stopped and forces a reset. The boot counter detects repeated failed attempts and switches slots. One health check decides the new software genuinely works, and confirms.&lt;/p&gt;

&lt;p&gt;Three rules make that practical. Define the health check as the smallest set of conditions meaning the device performs its function &lt;em&gt;and&lt;/em&gt; can be updated again, including the update agent's reachability. Keep the confirmation path independent of the application. And set &lt;code&gt;bootlimit&lt;/code&gt; to at least 3, so one transient failure does not cause a rollback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The boot counter alone is the right choice&lt;/strong&gt; in two situations. If a technician can reach and reflash a failed device, a dead application and a dead boot are the same service call. And if the application team cannot commit to a stable health signal, a check whose meaning changes every release produces rollbacks nobody can explain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A userspace check alone is the right choice&lt;/strong&gt; when the vendor boot chain is locked and you cannot add counting logic. Put the fallback decision in an initramfs or an early service that runs before the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequences
&lt;/h2&gt;

&lt;p&gt;The health check becomes release-critical code. It ships inside the image it validates, so version it with that image, and test the rollback path each release with a bundle known to fail.&lt;/p&gt;

&lt;p&gt;You acquire a timing budget. The watchdog timeout must exceed the worst-case boot, including a filesystem check and any first-boot migration; otherwise a slow but healthy boot is indistinguishable from a broken one. U-Boot's &lt;code&gt;CONFIG_WATCHDOG_TIMEOUT_MSECS&lt;/code&gt; defaults to 60000 with per-architecture overrides — measure it on your hardware.&lt;/p&gt;

&lt;p&gt;Rollback is not free at the data layer either. Returning to older software leaves newer data on the writable partition, so a schema written by the new version must still load on the old one — a constraint belonging to the application, not the update framework. You also need to explain a rollback afterwards, so record the watchdog boot status (&lt;code&gt;WDIOC_GETBOOTSTATUS&lt;/code&gt;, &lt;code&gt;WDIOF_CARDRESET&lt;/code&gt;) and &lt;code&gt;ustate&lt;/code&gt; or &lt;code&gt;BOOT_&amp;lt;bootname&amp;gt;_LEFT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, one boot confirmation failure mode is easy to miss. If no device in your fleet has ever rolled back, the likely explanation is not that every release was perfect; it is that the health check tests nothing. Keep a rescue system regardless, because a double-copy setup still has failure modes affecting both copies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A successful installation is not a successful update; boot confirmation decides whether the new slot is kept.&lt;/li&gt;
&lt;li&gt;A boot counter catches failures that never reach userspace; a health check catches a device that boots but does not work. Neither covers the other.&lt;/li&gt;
&lt;li&gt;A hardware watchdog turns a hang into a reset the counter can observe; under systemd it is off by default. Keep the health check small, and always include the ability to receive another update.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is boot confirmation?&lt;/strong&gt;&lt;br&gt;
It is the step where a newly booted system reports back to the bootloader that it is working, so the bootloader stops treating the new slot as unproven. Until then, returning to the previous slot stays possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a bootloader boot counter enough on its own?&lt;/strong&gt;&lt;br&gt;
Only when someone can physically reach a failed device, or when the application cannot provide a stable health signal. A counter measures boots, not correctness, so a device that boots with a dead application passes it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should the userspace health check actually test?&lt;/strong&gt;&lt;br&gt;
The smallest set of conditions meaning the device performs its function and can still receive another update. Include the update agent's reachability, so a bad release stays replaceable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is a hardware watchdog needed if the bootloader already counts boots?&lt;/strong&gt;&lt;br&gt;
A counter only increments when the device reboots. A system that hangs does not reboot, so the failure is never counted. The watchdog forces the reset that makes it visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.u-boot.org/en/latest/api/bootcount.html" rel="noopener noreferrer"&gt;U-Boot — Boot Count Limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rauc.readthedocs.io/en/latest/basic.html" rel="noopener noreferrer"&gt;RAUC Basics — Boot Confirmation and Fallback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rauc.readthedocs.io/en/latest/integration.html" rel="noopener noreferrer"&gt;RAUC Integration — bootloader backends and watchdog setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sbabic.github.io/swupdate/swupdate-best-practise.html" rel="noopener noreferrer"&gt;SWUpdate Best Practice — update concept, ustate and fallback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html" rel="noopener noreferrer"&gt;The Linux Watchdog driver API — magic close and nowayout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/latest/systemd-system.conf.html" rel="noopener noreferrer"&gt;systemd-system.conf(5) — RuntimeWatchdogSec&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/09/19/boot-confirmation-update-rollback/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;. I teach Linux kernel and embedded Linux courses at &lt;a href="https://www.techveda.live/" rel="noopener noreferrer"&gt;TECH VEDA&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

</description>
      <category>embedded</category>
      <category>linux</category>
      <category>iot</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
