<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl" media="all"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Roastidio.us Tagged with linux</title>
<link>https://roastidio.us/tag/2428</link>
<atom:link href="https://roastidio.us/tagged_with/linux" rel="self" type="application/rss+xml"></atom:link>
<description>Roastidio.us Tagged with linux</description>
<item>
<title>Clean your Mac &amp; Windows/Linux PC with Disk Space – SOS</title>
<link>https://shaneosullivan.wordpress.com/2026/09/03/clean-your-mac-windows-linux-pc-with-disk-space/</link>
<enclosure type="image/jpeg" length="0" url="https://shaneosullivan.wordpress.com/wp-content/uploads/2026/09/screenshot-2026-09-03-at-09.36.21.png"></enclosure>
<guid isPermaLink="false">vEWo9n8yw1VWp1X4M3wy0TKgAlu3YTwcIchoIQ==</guid>
<pubDate>Wed, 16 Sep 2026 04:07:11 +0000</pubDate>
<description>TLDR: Download the best disk cleanup app in existence from diskspace.io. A fun experiment in writing the same app three times (well kind of 4 times) with AI, and being as optimised and OS native as…</description>
<content:encoded>&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt;: Download the best disk cleanup app in existence from diskspace.io. A fun experiment in writing the same app three times (well kind of 4 times) with AI, and being as optimised and OS native as possible.&lt;br/&gt;&lt;br/&gt;My Mac recently filled its 1TB drive and my quest to find out where the space had gone was very frustrating.  The existing tools for tracking down disk space were slow, clunky and it was impossible to use them until their 30 minute crawl of my hard drive completed.&lt;/p&gt;&lt;figure&gt;&lt;a href=&quot;https://shaneosullivan.wordpress.com/wp-content/uploads/2026/09/screenshot-2026-09-03-at-08.03.11-2.png&quot;&gt;&lt;img src=&quot;https://shaneosullivan.wordpress.com/wp-content/uploads/2026/09/screenshot-2026-09-03-at-08.03.11-2.png?w=1024&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p&gt;I decided to fix this by building a new app called Disk Space, which takes the great features of my favourite old time app Disk Inventory X, makes it blazingly fast and adds much improved file/folder deletion aesthetics so that you can clean up safely and quickly, as well as highlighting recently created files so you can find what changed more quickly.&lt;/p&gt;&lt;h2&gt;Let’s get nerdy&lt;/h2&gt;&lt;p&gt;The three versions, Mac, Windows and Linux, are all mostly independent, with just a little shared C++ code.  My goal was to make each app as small, fast, as native to its environment as possible.  This meant not using any of the more common cross platform libraries, and leaning on Claude to do the work.&lt;/p&gt;&lt;figure&gt;&lt;a href=&quot;https://shaneosullivan.wordpress.com/wp-content/uploads/2026/09/screenshot-2026-09-03-at-09.36.21.png&quot;&gt;&lt;img src=&quot;https://shaneosullivan.wordpress.com/wp-content/uploads/2026/09/screenshot-2026-09-03-at-09.36.21.png?w=632&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;h3&gt;MacOS&lt;/h3&gt;&lt;p&gt;The MacOS version of Disk Space is written fully in Swift, with no dependencies on other libraries.  This was the first version I built.  It detects how many CPU cores your machine has and optimises itself to maximise the throughput.  The size of the installed app is just under 1MB, with about 300KB of that being multiple sizes of the icon, so the app itself is just over 600KB in size. Not bad!&lt;/p&gt;&lt;p&gt;Releasing desktop apps for the Mac is actually not too bad an experience.  You can choose to put it in the App Store, but then it can be a pain to release a new version.  Apple offer a free notarisation service that signs the built app with your Apple Developer credentials, and it works well.  For this reason, you can simply download the MacOS version of Disk Space from the site.&lt;/p&gt;&lt;h3&gt;Windows&lt;/h3&gt;&lt;p&gt;The Windows version is a direct port of the Swift code to C++.  Similar to the MacOS version it optimises its operation based on the number of cores, but it also checks if the drive being scanned is a spinning disk or a solid state drive.  If it’s a spinning disk there’s no point running many threads against it, it’s physically incapable of responding, so it caps the number of threads.  Since it it just pure C++ with no dependencies pulled in, the installer is just about 600KB, pretty cool.&lt;/p&gt;&lt;p&gt;Releasing apps on Windows these days generally means you are forced to either release through the Microsoft Store or pay for quite expensive yearly fees to have your app notarized.  Without this, the user will be shown very scary warning dialogs, making the app very hostile to use.  Since this is a small free app, I went the &lt;a href=&quot;https://apps.microsoft.com/detail/9nwpgvh9rp8l&quot;&gt;Microsoft Store&lt;/a&gt; route.  &lt;/p&gt;&lt;h3&gt;Linux&lt;/h3&gt;&lt;p&gt;The Linux version shares some of the C++ with the Windows version, especially the code that draws the multi-coloured tree map on the right.  Similar to the Windows version, it checks the hardware of your storage to best optimize itself and otherwise builds the UI using Linux native code with almost not dependencies.  The first version Claude recommended depended on the GTK libraries for the UI, which was convenient, but it meant that using the app on any system that didn’t include those libraries would force the user to download hundreds of megabytes just to get a 500KB app running.  Luckily, within an hour Claude had completely rewritten the app to be almost fully self contained.&lt;/p&gt;&lt;p&gt;This means that the Linux app, which is packaged as an AppImage file, is just about 600KB all in, and you can simply download it from the site.&lt;/p&gt;&lt;figure&gt;&lt;div&gt;

&lt;/div&gt;&lt;/figure&gt;&lt;h3&gt;Epilogue&lt;/h3&gt;&lt;p&gt;This was a fun experiment in building an identical app for all three operating systems while keeping it as native and optimised as possible.  The hardest part was the hardware setup required for testing.&lt;/p&gt;&lt;p&gt;I now have on my desk:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;My MacBook Pro (my primary machine).  I do most of my work on this, run Claude and do all testing of the MacOS app.&lt;/li&gt;



&lt;li&gt;A small but powerful Windows Desktop.  This is pretty great, as not only can Claude build and test Windows apps on it, it can also build and test (to some degree) Linux apps too.  I use this as the main machine for those two operating systems.&lt;/li&gt;



&lt;li&gt;An ancient, 2009 MacBook Pro 17″ that I installed Linux on just for building this app.  I use this for testing the Linux version on a real machine, not just on Windows WSL.  It works relatively well, but with just 4GB of memory I won’t be doing any development on it any time soon.  Still, it’s great to make use of the old hardware instead of throwing it away – I knew there was a reason I hung on to it!&lt;/li&gt;



&lt;li&gt;… a lot of messy crap I need to tidy up.  Any day now….&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I can’t believe you read this far, thanks!  Now go get Disk Space from diskspace.io, your hard drive will thank you 🙂&lt;/p&gt;&lt;p&gt;&lt;br/&gt; &lt;/p&gt;</content:encoded>
</item>
<item>
<title>Switching to GNU Guix: a beginner’s perspective</title>
<link>https://www.osnews.com/story/145960/switching-to-gnu-guix-a-beginners-perspective/</link>
<guid isPermaLink="false">LTbX9XDiWJlC486TZIVBjapAhq1pceXJs00orA==</guid>
<pubDate>Tue, 15 Sep 2026 23:42:32 +0000</pubDate>
<description>Want to run something a little more exotic on your server? How about GNU Guix? It has been a month since migrating my home server to GNU Guix. Managing OS state declaratively through Git has eliminated configuration drift, and Guile Scheme provides a cohesive environment that complements Emacs. While adapting to a smaller package ecosystem and managing substitute timing requires occasional adjustments, the stability, reproducibility, and container isolation make it a dependable foundation. ...</description>
<content:encoded>&lt;p&gt;Want to run something a little more exotic on your server? How about GNU Guix?&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It has been a month since migrating my home server to GNU Guix. Managing OS state declaratively through Git has eliminated configuration drift, and Guile Scheme provides a cohesive environment that complements Emacs. While adapting to a smaller package ecosystem and managing substitute timing requires occasional adjustments, the stability, reproducibility, and container isolation make it a dependable foundation.&lt;/p&gt;&lt;cite&gt;&lt;a href=&quot;https://whhone.com/posts/switching-to-gnu-guix/&quot;&gt;↫ Wai Hon&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;&lt;p&gt;I’m definitely noticing an increase in interest in Guix lately.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Network Subsystem | Internals for Interns</title>
<link>https://internals-for-interns.com/posts/linux-kernel-network-subsystem/</link>
<enclosure type="image/jpeg" length="0" url="https://internals-for-interns.com/images/linux-header.webp"></enclosure>
<guid isPermaLink="false">TXjvguS1x2gB2tuW84Fp-9LMnALUmbAw7jPiPQ==</guid>
<pubDate>Tue, 15 Sep 2026 21:45:20 +0000</pubDate>
<description>At the end of the previous article we watched a module fill in a struct net_device_ops (include/linux/netdevice.h:1436), hand it to register_netdev() (net/core/dev.c:11531), and walk away. That’s a promise: here are my function pointers, call me when you need the hardware. What we never got to see is the other half of the promise — who calls them, and what happens in between the wire and your program. So let’s go look. We’re going to follow one packet all the way in, and then one pack...</description>
<content:encoded>&lt;p&gt;At the end of the &lt;a href=&quot;https://internals-for-interns.com/posts/linux-kernel-module-system/&quot;&gt;previous article&lt;/a&gt;
we watched a module fill in a &lt;code&gt;struct net_device_ops&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/linux/netdevice.h#L1436&quot;&gt;&lt;code&gt;include/linux/netdevice.h:1436&lt;/code&gt;&lt;/a&gt;), hand it to &lt;code&gt;register_netdev()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/dev.c#L11531&quot;&gt;&lt;code&gt;net/core/dev.c:11531&lt;/code&gt;&lt;/a&gt;), and walk away. That’s a promise: &lt;em&gt;here are my function pointers, call me when you need the hardware&lt;/em&gt;. What we never got to see is the other half of the promise — who calls them, and what happens in between the wire and your program.&lt;/p&gt;&lt;p&gt;So let’s go look. We’re going to follow one packet all the way in, and then one packet all the way back out.&lt;/p&gt;&lt;p&gt;The setup is deliberately boring. A server is listening on port 8080 on your machine, blocked in &lt;code&gt;recv()&lt;/code&gt;, waiting. Somewhere out on the network a client sends a small HTTP request, which gets wrapped into a TCP packet, travels across the internet, and eventually arrives at your machine’s network card. Several stops later, &lt;code&gt;recv()&lt;/code&gt; returns with that request in a buffer. Then the server writes a reply, and the whole thing runs backwards.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;📌 A note on scope&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Everything here is against Linux &lt;strong&gt;7.1&lt;/strong&gt;, following &lt;strong&gt;IPv4 and TCP over Ethernet&lt;/strong&gt;. And as always, this is a deliberate simplification: some things I’ve flattened out, and a few I’ve left out entirely.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Before we start walking, let’s be clear about what it is we’re following.&lt;/p&gt;&lt;h2&gt;Four layers, four headers&lt;/h2&gt;&lt;p&gt;If you’ve written socket code most of this will be familiar, but it’s worth stating plainly, because the shape of the stack &lt;em&gt;is&lt;/em&gt; the shape of this article.&lt;/p&gt;&lt;p&gt;Start with the part that catches people out: &lt;strong&gt;the kernel has no idea what HTTP is.&lt;/strong&gt; It never sees a request line, never parses a header. What it offers is a stream of bytes that arrives complete and in the right order; making those bytes &lt;em&gt;mean&lt;/em&gt; something is the application’s job. Building that stream means wrapping the data in layers, each one solving exactly one problem and adding a header to record how it solved it:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Layer&lt;/th&gt;&lt;th&gt;The problem it solves&lt;/th&gt;&lt;th&gt;How it identifies it&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;HTTP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;What do these bytes &lt;em&gt;mean&lt;/em&gt;?&lt;/td&gt;&lt;td&gt;the application’s job, not the kernel’s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TCP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Which program does this go to, and did it all arrive in order?&lt;/td&gt;&lt;td&gt;port numbers, sequence numbers&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Which machine on the internet do we send it to?&lt;/td&gt;&lt;td&gt;IP addresses&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ethernet&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Which device on this cable do we hand it to?&lt;/td&gt;&lt;td&gt;MAC addresses&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;So we have four layers, each solving one problem and leaving a header behind to record how it solved it. On the way out a packet picks them up one at a time; on the way in it sheds them the same way. That’s the shape of everything that follows — but let’s start at the beginning.&lt;/p&gt;&lt;h2&gt;The arrival&lt;/h2&gt;&lt;p&gt;So: the frame is on the cable your machine is plugged into. Never mind how it got there — at this point it’s just an electrical signal on the wire, and the card’s hardware is what turns that signal into bytes.&lt;/p&gt;&lt;p&gt;The very front of those bytes is the Ethernet header, starting with the &lt;strong&gt;destination MAC address&lt;/strong&gt;. That’s the only question the card cares about right now: &lt;em&gt;is this frame for me?&lt;/em&gt; It compares that address against its own, and if it doesn’t match, the frame is discarded on the spot and nobody is told — as far as your kernel is concerned, it never existed.&lt;/p&gt;&lt;p&gt;Ours matches. So what we have is a frame, addressed to us, sitting in a tiny buffer on the card, with the next frame possibly already arriving behind it.&lt;/p&gt;&lt;p&gt;And this is where the kernel starts getting involved.&lt;/p&gt;&lt;h2&gt;How the card and the kernel share memory&lt;/h2&gt;&lt;p&gt;Normally, when something happens out in the physical world, the way the hardware tells the operating system about it is an &lt;strong&gt;interrupt&lt;/strong&gt;: the CPU stops what it was doing, and the kernel drops everything to go and deal with the event. That’s a perfectly good arrangement for a keypress, or a disk finishing a read. It falls apart completely when packets are arriving in their millions every second.&lt;/p&gt;&lt;p&gt;So network cards work a different way. Instead of announcing each packet and waiting to be served, the card and the kernel agree &lt;em&gt;in advance&lt;/em&gt; to share some memory, and the card writes packets straight into it using &lt;strong&gt;DMA&lt;/strong&gt; — &lt;em&gt;direct memory access&lt;/em&gt;, where the device reads and writes RAM without the CPU moving a single byte. The data is delivered first, and the kernel is told about it afterwards.&lt;/p&gt;&lt;p&gt;Let’s look at how that’s arranged:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://internals-for-interns.com/images/linux-kernel-network-descriptor-ring.webp&quot; alt=&quot;Diagram of a network card and main memory sharing a descriptor ring. On the left, a box labelled NETWORK CARD contains a hatched rectangle labelled ’tiny buffer, kilobytes’ and, below it, a smaller box labelled ‘doorbell register’; an arrow enters the card from outside the diagram labelled ‘frame arrives’. On the right, a large rounded region labelled MAIN MEMORY holds two groups. At the top, a horizontal strip of six slots labelled DESCRIPTOR RING, two of them holding addresses written as 0x…, with a curved arrow at its right-hand end annotated ‘circular’. Below it, a column of four rectangles labelled PAGES, braced with the note ‘kernel memory, mapped for DMA’; the bottom page is hatched and highlighted. A dotted arrow runs from one ring slot down to that highlighted page, showing which page the slot points at. A thick highlighted arrow labelled DMA runs from the card across into that same page, and a separate plain arrow runs from the descriptor ring back to the card&quot; title=&quot;&quot;/&gt;&lt;/p&gt;&lt;p&gt;The card is on the left, holding our frame in that tiny buffer. Main memory is on the right. And the thing that joins them is the &lt;strong&gt;descriptor ring&lt;/strong&gt;: a circular array of small records, living in main memory, that &lt;em&gt;both sides&lt;/em&gt; read and write. Each record — a &lt;strong&gt;descriptor&lt;/strong&gt; — is a small fixed-size struct, and the two sides take turns writing into it.&lt;/p&gt;&lt;p&gt;Two things are worth being precise about here. The first is that the descriptor’s layout isn’t the kernel’s to choose. It’s dictated by the hardware and written down in the card’s datasheet, field by field and bit by bit. Knowing it is a large part of what a network card driver &lt;em&gt;is&lt;/em&gt;, and it’s why the driver has to be card-specific while everything above it isn’t.&lt;/p&gt;&lt;p&gt;The second is that &lt;strong&gt;the ring never holds packet data&lt;/strong&gt;. Not one byte of our frame goes into it. A descriptor only ever &lt;em&gt;describes&lt;/em&gt; a transfer. The frame itself lives in the pages underneath, and the descriptor just tells you where.&lt;/p&gt;&lt;p&gt;So that’s the arrangement: the driver keeps the ring stocked with pages mapped for DMA, and tells the card they’re there by &lt;strong&gt;ringing the doorbell&lt;/strong&gt; — writing a slot number into a register on the card (the little box in the diagram) that means “everything up to slot N is yours”. That happens once at startup, and again every time the packets in some slots have been consumed and the driver has made those slots ready to receive more.&lt;/p&gt;&lt;p&gt;The card’s side of the bargain is the other direction. It DMAs the frame into one of those pages, writes the length and status back into the descriptor, and only then raises an interrupt.&lt;/p&gt;&lt;p&gt;And that interrupt doesn’t mean “here is a packet”, it means “there is traffic”. Interrupts for that queue then go quiet and the kernel &lt;strong&gt;polls&lt;/strong&gt; the ring until it drains, so a whole batch of frames costs one interrupt instead of one each.&lt;/p&gt;&lt;p&gt;Turning that page of bytes into something the rest of the stack can work with takes one more object.&lt;/p&gt;&lt;h2&gt;One object does all the travelling&lt;/h2&gt;&lt;p&gt;That object is the &lt;strong&gt;&lt;code&gt;sk_buff&lt;/code&gt;&lt;/strong&gt; — the &lt;em&gt;socket buffer&lt;/em&gt;, universally called an &lt;strong&gt;skb&lt;/strong&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/linux/skbuff.h#L886&quot;&gt;&lt;code&gt;include/linux/skbuff.h:886&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;An skb is not the packet itself. It’s the packet’s &lt;em&gt;paperwork&lt;/em&gt;: a metadata object holding a handful of pointers into the buffer where the bytes actually live. That separation is the point — a packet crosses several layers on its way through the kernel, and copying or shuffling its bytes at every handoff would be ruinously expensive, so what gets passed around is the skb, never the data. And the way those pointers move is the whole trick:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://internals-for-interns.com/images/linux-kernel-network-skb-headroom.webp&quot; alt=&quot;Diagram of one skb buffer at four moments in time, drawn as four stacked horizontal strips of identical width and alignment. In the top strip, small arrows label head at the far left edge, data in the middle and end at the far right; everything left of data is hatched and labelled HEADROOM, and everything right of it is a shaded block labelled PAYLOAD. In the second strip a band labelled TCP HEADER has appeared immediately to the left of the payload, taking a bite out of the hatched headroom, and the data arrow has moved left to the start of that band. In the third strip an IP HEADER band sits to the left of the TCP header and data has moved left again, leaving only a small hatched region. In the fourth strip an ETHERNET HEADER band has been added to the left of the IP header and data has moved left once more, with barely any headroom remaining. A vertical dashed line runs down through all four strips, touching the left edge of the payload block in every one, annotated at the bottom with the note: the payload never moves&quot; title=&quot;&quot;/&gt;&lt;/p&gt;&lt;p&gt;Look at the top strip first. &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; mark the memory that was allocated, and &lt;code&gt;data&lt;/code&gt; marks where the packet currently begins. The hatched gap between &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; is the &lt;strong&gt;headroom&lt;/strong&gt; — deliberately empty space, set aside in front of the payload before anyone has asked for it.&lt;/p&gt;&lt;p&gt;Let’s start by thinking about how the skb is built on its way out. It begins with the payload and some empty headroom in front of it, and as it travels down the stack each layer writes its own header into that space — TCP’s, then IP’s, then Ethernet’s. The payload is never copied and the buffer is never reallocated; the &lt;code&gt;data&lt;/code&gt; pointer just moves backwards to wherever the packet now begins. Once the bottom layer is done, the whole thing goes out on the wire.&lt;/p&gt;&lt;p&gt;Coming in, it’s the same picture read from the bottom up. The headers are already there, and each layer handles its own and then moves &lt;code&gt;data&lt;/code&gt; forwards past it, so the layer above receives an skb whose &lt;code&gt;data&lt;/code&gt; points at exactly the header it cares about. Every layer only ever has to think about its own.&lt;/p&gt;&lt;p&gt;So our frame is in memory, wrapped in an object the kernel can hand from layer to layer and address one protocol at a time. Let’s follow it up the stack.&lt;/p&gt;&lt;h2&gt;GRO: Generic Receive Offload&lt;/h2&gt;&lt;p&gt;The obvious next move is to hand it up to IP — but the driver calls &lt;code&gt;napi_gro_receive()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/linux/netdevice.h#L4286&quot;&gt;&lt;code&gt;include/linux/netdevice.h:4286&lt;/code&gt;&lt;/a&gt;) instead.&lt;/p&gt;&lt;p&gt;Here’s why. Ethernet caps a frame at around 1500 bytes, so a 1 MB download turns up as some seven hundred separate packets. Taken one at a time, each has to climb the whole stack: IP checks it, routing looks at it, TCP finds the socket and queues the bytes. Seven hundred rounds of that, for what is really one lump of data chopped up for the journey.&lt;/p&gt;&lt;p&gt;So GRO — &lt;em&gt;Generic Receive Offload&lt;/em&gt; — glues the pieces back together first. &lt;code&gt;dev_gro_receive()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/gro.c#L474&quot;&gt;&lt;code&gt;net/core/gro.c:474&lt;/code&gt;&lt;/a&gt;) hashes the flow, and if it’s already holding a packet from that same conversation, it asks whether the newcomer is a legal continuation: same addresses and ports, sequence numbers exactly adjacent, nothing odd in the flags. If so, the payload is tacked on as another page fragment and the new skb disappears.&lt;/p&gt;&lt;p&gt;A run of back-to-back segments therefore collapses into a &lt;em&gt;single&lt;/em&gt; skb of up to 64 KB, which crosses IP and TCP &lt;strong&gt;once&lt;/strong&gt; instead of forty-five times.&lt;/p&gt;&lt;p&gt;GRO read the headers, but only to work out what could merge with what. Nothing has yet decided where the packet actually goes.&lt;/p&gt;&lt;h2&gt;Who does this packet belong to?&lt;/h2&gt;&lt;p&gt;However it got here — merged with others or on its own — our skb now reaches &lt;code&gt;__netif_receive_skb_core()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/dev.c#L5972&quot;&gt;&lt;code&gt;net/core/dev.c:5972&lt;/code&gt;&lt;/a&gt;), the device layer’s last act before the packet is handed to a protocol, IP in our case. It runs a fixed sequence of steps, always in the same order:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Housekeeping.&lt;/strong&gt; Small fixups, like stripping off a VLAN tag if the card didn’t already do it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The taps.&lt;/strong&gt; Any socket that asked to see &lt;em&gt;everything&lt;/em&gt; gets a copy right here. This is where &lt;code&gt;tcpdump&lt;/code&gt; gets your packet — and note that it happens &lt;em&gt;before&lt;/em&gt; any firewalling, which is exactly why &lt;code&gt;tcpdump&lt;/code&gt; cheerfully shows you packets that iptables then drops.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;tc and netfilter ingress.&lt;/strong&gt; The first step that can actually intervene: BPF programs and traffic-control filters attached to the interface run here, and they may drop the packet or send it somewhere else entirely.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The &lt;code&gt;rx_handler&lt;/code&gt;.&lt;/strong&gt; A hook (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/linux/netdevice.h#L2189&quot;&gt;&lt;code&gt;include/linux/netdevice.h:2189&lt;/code&gt;&lt;/a&gt;) that lets a virtual device steal packets from a physical one. It’s how bridges, bonding and macvlan get their traffic before the kernel decides it was meant for this machine.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The protocol demux.&lt;/strong&gt; And finally the actual question: what’s inside this frame, and who handles it?&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That last step is how the packet reaches IP at all, and the mechanism is refreshingly plain. The Ethernet header ends with two bytes called the &lt;strong&gt;EtherType&lt;/strong&gt;, which say what kind of packet is wrapped inside it. The kernel takes those two bytes and looks them up in a hash table of protocols that registered themselves at boot. IPv4 is simply one entry in that table (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/af_inet.c#L1881&quot;&gt;&lt;code&gt;net/ipv4/af_inet.c:1881&lt;/code&gt;&lt;/a&gt;), saying “EtherType 0x0800 goes to &lt;code&gt;ip_rcv&lt;/code&gt;”.&lt;/p&gt;&lt;p&gt;And if nothing matches? The packet is dropped with a &lt;em&gt;named&lt;/em&gt; reason. That’s a habit worth noticing, because it’s everywhere in this stack: nearly every place a packet can die tags itself, so you can always find out exactly why something vanished.&lt;/p&gt;&lt;p&gt;Ours is 0x0800. Off to IP.&lt;/p&gt;&lt;h2&gt;IP&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ip_rcv()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/ip_input.c#L603&quot;&gt;&lt;code&gt;net/ipv4/ip_input.c:603&lt;/code&gt;&lt;/a&gt;) starts with the unglamorous part: is this packet even real? Wrong version, truncated header, bad header checksum, a total length that doesn’t fit the buffer — dropped, each with its own reason code.&lt;/p&gt;&lt;p&gt;Next the packet goes through &lt;strong&gt;netfilter&lt;/strong&gt;, the machinery behind &lt;code&gt;iptables&lt;/code&gt; and friends. What’s interesting here isn’t what it does but the &lt;em&gt;shape&lt;/em&gt; of the call: every netfilter hook takes, as its last argument, the function to call &lt;em&gt;if the packet survives&lt;/em&gt;. You don’t ask the firewall for a verdict and carry on — you hand the firewall your continuation.&lt;/p&gt;&lt;p&gt;Assuming the packet lives, IP has one real question left: &lt;strong&gt;where is this going?&lt;/strong&gt; Answering it means a &lt;strong&gt;route lookup&lt;/strong&gt; — walking the routing table to work out whether this packet is for us or for somebody else, and attaching that answer to the skb as a &lt;code&gt;dst_entry&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/net/dst.h#L26&quot;&gt;&lt;code&gt;include/net/dst.h:26&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;There’s a shortcut, though. Before routing, IP looks up the &lt;em&gt;socket&lt;/em&gt; — &lt;code&gt;tcp_v4_early_demux()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/ip_input.c#L322&quot;&gt;&lt;code&gt;net/ipv4/ip_input.c:322&lt;/code&gt;&lt;/a&gt;), and if it finds an established connection it borrows the route that socket already has.&lt;/p&gt;&lt;p&gt;Our packet is for us, so it’s handed to &lt;code&gt;ip_local_deliver&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/ip_input.c#L250&quot;&gt;&lt;code&gt;net/ipv4/ip_input.c:250&lt;/code&gt;&lt;/a&gt;), which runs one more netfilter hook, strips the IP header off the front, and looks up the protocol number in a registration table — the same trick as the EtherType table, one layer up. Protocol 6 is TCP, registered to &lt;code&gt;tcp_v4_rcv&lt;/code&gt;.&lt;/p&gt;&lt;h2&gt;TCP&lt;/h2&gt;&lt;p&gt;&lt;code&gt;tcp_v4_rcv()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp_ipv4.c#L2068&quot;&gt;&lt;code&gt;net/ipv4/tcp_ipv4.c:2068&lt;/code&gt;&lt;/a&gt;) checks the TCP checksum and works out which socket the packet belongs to, by looking up four numbers — source and destination address, source and destination port — in a table of open connections.&lt;/p&gt;&lt;p&gt;Right now we’re running in kernel code, kicked off by the card’s interrupt, and the data has to end up in the socket’s receive queue. The catch is that your program might be sitting in a syscall on that very socket at this moment — also in kernel code, also reaching for that same queue. The two of them have to coordinate, and the way they do it is the &lt;strong&gt;socket lock&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;If nobody holds the lock, this code takes it and does TCP’s work straight away — sequence numbers, windows, ACKs, queueing the data — before your program has even woken up. If your thread is holding it, though, we can’t simply wait our turn: this is the kernel’s deferred packet-processing context, which isn’t allowed to sleep, and blocking here would stall packet processing for everyone else on the machine. So the packet is parked on the socket’s &lt;strong&gt;backlog&lt;/strong&gt; queue, and the thread holding the lock inherits the job, doing it on its way back out of the syscall.&lt;/p&gt;&lt;p&gt;Either way the data ends up where it belongs, in &lt;code&gt;tcp_data_queue()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp_input.c#L5574&quot;&gt;&lt;code&gt;net/ipv4/tcp_input.c:5574&lt;/code&gt;&lt;/a&gt;): bytes that arrived in order go onto the socket’s &lt;strong&gt;receive queue&lt;/strong&gt;, ready to be read, and anything that arrived early — the packet after one that got lost — waits until the gap is filled.&lt;/p&gt;&lt;p&gt;Then somebody needs telling. TCP calls the socket’s &lt;code&gt;sk_data_ready&lt;/code&gt; callback (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/sock.c#L3614&quot;&gt;&lt;code&gt;net/core/sock.c:3614&lt;/code&gt;&lt;/a&gt;), which wakes anything sleeping on the socket. &lt;strong&gt;This is the wakeup that ends a blocking &lt;code&gt;recv()&lt;/code&gt;, and the one that makes an &lt;code&gt;epoll_wait()&lt;/code&gt; return&lt;/strong&gt;.&lt;/p&gt;&lt;h2&gt;&lt;code&gt;recv()&lt;/code&gt; finally returns&lt;/h2&gt;&lt;p&gt;All this time our server thread has been asleep — not spinning, not checking anything, just parked and taken off the run queue, waiting inside &lt;code&gt;recvfrom()&lt;/code&gt;. The &lt;a href=&quot;https://internals-for-interns.com/posts/linux-kernel-syscalls/&quot;&gt;syscall&lt;/a&gt;
had carried it into &lt;code&gt;tcp_recvmsg()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp.c#L2931&quot;&gt;&lt;code&gt;net/ipv4/tcp.c:2931&lt;/code&gt;&lt;/a&gt;), which locked the socket, found nothing to read, and put the thread to sleep.&lt;/p&gt;&lt;p&gt;The wakeup we just fired puts it back on the run queue, and it carries on from exactly where it stopped: walk the receive queue to find the skb holding the next byte the application hasn’t read, copy those bytes into the buffer the application handed to &lt;code&gt;recv()&lt;/code&gt;, note how far it has got, and free the skbs that are now fully drained.&lt;/p&gt;&lt;p&gt;One last thing happens on the way out, in &lt;code&gt;release_sock()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/sock.c#L3819&quot;&gt;&lt;code&gt;net/core/sock.c:3819&lt;/code&gt;&lt;/a&gt;). Remember the backlog, where packets got parked because our thread was holding the socket lock? Those get processed &lt;em&gt;now&lt;/em&gt;, in our thread, before the lock is released. Your application quietly pays the CPU cost of its own protocol processing, inside its own syscall.&lt;/p&gt;&lt;p&gt;And then &lt;code&gt;recv()&lt;/code&gt; returns, with the request sitting in the application’s buffer. The journey in is over — and it’s worth seeing the whole of it in one picture before we turn around:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://internals-for-interns.com/images/linux-kernel-network-receive-path.webp&quot; alt=&quot;Diagram of the inbound packet path, drawn as a tall vertical flow read from the bottom upwards and split into three bands by dashed horizontal lines, labelled HARDWARE at the bottom, KERNEL in the middle and APPLICATION at the top. In the hardware band, a wavy line labelled ’the wire’ enters a box labelled NETWORK CARD, annotated ‘is this MAC mine?’. Two arrows rise from the card into the kernel band: a thick highlighted one labelled DMA, and a zigzag one labelled ‘interrupt’. The kernel band holds a vertical column of boxes joined by upward arrows: PAGE (raw bytes), then skb (the paperwork), then GRO (merge with siblings), then DEVICE LAYER (who owns this?) annotated ‘EtherType 0x0800 goes to IP’, then IP (valid? route it) annotated ‘protocol 6 goes to TCP’, then TCP (find the socket), then RECEIVE QUEUE. A side box labelled BACKLOG sits to the left of the TCP box, joined to it by a two-way arrow and annotated ‘handled later, by the app’s own thread’. From RECEIVE QUEUE a highlighted arrow labelled ‘wake up!’ crosses into the application band and points at a box labelled ‘recv() returns’, which has a small box beside it labelled ‘user buffer’. To its left, a dashed box labelled ‘server thread, asleep’ has an arrow pointing across to it&quot; title=&quot;&quot;/&gt;&lt;/p&gt;&lt;p&gt;Notice how much of that column is spent working out &lt;em&gt;who&lt;/em&gt; the packet belongs to — the MAC, the EtherType, the protocol number, the socket — and how little of it touches the data itself. The way back out inverts that completely. The destination is known from the very first line, and nearly all the work goes into deciding &lt;em&gt;when&lt;/em&gt; to send.&lt;/p&gt;&lt;h2&gt;The way out&lt;/h2&gt;&lt;p&gt;Our server writes its reply — a short HTTP response — with &lt;code&gt;send()&lt;/code&gt;. The thing to understand about the transmit path is that copying and sending are two separate steps: &lt;code&gt;send()&lt;/code&gt; always does the first, and then asks whether to do the second.&lt;/p&gt;&lt;p&gt;&lt;code&gt;tcp_sendmsg_locked()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp.c#L1117&quot;&gt;&lt;code&gt;net/ipv4/tcp.c:1117&lt;/code&gt;&lt;/a&gt;) looks at the tail of the socket’s &lt;strong&gt;write queue&lt;/strong&gt;. If there’s an skb there with room left, it appends to it; if not, it allocates a fresh one (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp.c#L927&quot;&gt;&lt;code&gt;net/ipv4/tcp.c:927&lt;/code&gt;&lt;/a&gt;) — and the first thing that allocation does is reserve a couple of hundred bytes of headroom before putting any payload in. That’s the diagram from earlier, set up in advance: every header this packet will ever need — TCP, IP, Ethernet, any tunnelling in between — has already been paid for, right here, at copy time. Nothing further down the path will have to reallocate anything; each layer will just move the &lt;code&gt;data&lt;/code&gt; pointer backwards into space that has been waiting for it. The skb is also marked as needing only a partial checksum, because the card will finish that job later, so nobody wastes cycles on it now.&lt;/p&gt;&lt;p&gt;Then the payload is copied in, from the user’s buffer into kernel pages attached to the skb, and the write sequence number advances. That’s the copy done. Whether any of it actually goes out is a separate question, and it gets asked next.&lt;/p&gt;&lt;p&gt;At the very end, &lt;code&gt;tcp_push()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp.c#L741&quot;&gt;&lt;code&gt;net/ipv4/tcp.c:741&lt;/code&gt;&lt;/a&gt;) decides whether to actually try transmitting, and it has a nice trick called &lt;strong&gt;autocorking&lt;/strong&gt;: if there’s already data of ours queued further down that hasn’t gone out yet, don’t transmit at all. Mark the socket as throttled and return. The bet is that the application is in a write loop and the next &lt;code&gt;send()&lt;/code&gt; will land in the same skb, turning several small packets into one bigger one — a bet the kernel wins constantly, because applications really do write in loops.&lt;/p&gt;&lt;p&gt;Sooner or later, though, the data does have to go out, and that decision is nowhere near a simple yes or no.&lt;/p&gt;&lt;h2&gt;Deciding when to send&lt;/h2&gt;&lt;p&gt;&lt;code&gt;tcp_write_xmit()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp_output.c#L2963&quot;&gt;&lt;code&gt;net/ipv4/tcp_output.c:2963&lt;/code&gt;&lt;/a&gt;) walks the write queue and puts each skb through a series of gates. Any one of them can stop the loop dead:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Gate&lt;/th&gt;&lt;th&gt;The question it asks&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Pacing&lt;/td&gt;&lt;td&gt;Is it too early to send this, at our current pacing rate?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Congestion window&lt;/td&gt;&lt;td&gt;Does the &lt;em&gt;network&lt;/em&gt; have room for more unacknowledged data?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Receive window&lt;/td&gt;&lt;td&gt;Does the &lt;em&gt;peer&lt;/em&gt; have room?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nagle&lt;/td&gt;&lt;td&gt;Is this a small packet we should hold, hoping for more?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TSO deferral&lt;/td&gt;&lt;td&gt;Would waiting briefly let us build a bigger, cheaper segment?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Split to MSS&lt;/td&gt;&lt;td&gt;Is it too big for one segment, and needs cutting?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TCP Small Queues&lt;/td&gt;&lt;td&gt;Do we already have too many bytes in flight &lt;em&gt;locally&lt;/em&gt;?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Six of those seven are classic TCP. The last one isn’t about the network at all. &lt;strong&gt;TCP Small Queues&lt;/strong&gt;, or &lt;strong&gt;TSQ&lt;/strong&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp_output.c#L2856&quot;&gt;&lt;code&gt;net/ipv4/tcp_output.c:2856&lt;/code&gt;&lt;/a&gt;) caps how many bytes a single socket may have sitting in the &lt;em&gt;local&lt;/em&gt; transmit queues.&lt;/p&gt;&lt;p&gt;When the limit is hit, the socket is marked throttled and transmission stops. Which raises the obvious question: who restarts it? Hold that thought.&lt;/p&gt;&lt;h2&gt;Headers, added backwards&lt;/h2&gt;&lt;p&gt;An skb that gets through all that reaches &lt;code&gt;__tcp_transmit_skb()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/tcp_output.c#L1529&quot;&gt;&lt;code&gt;net/ipv4/tcp_output.c:1529&lt;/code&gt;&lt;/a&gt;), which starts by &lt;strong&gt;cloning&lt;/strong&gt; it. TCP can’t throw data away until the other end acknowledges it, so the original waits in the retransmit queue and only the clone goes down the stack — and since an skb is only paperwork, cloning copies the paperwork, not the bytes. Then the TCP header goes on, written into the headroom reserved back in &lt;code&gt;sendmsg&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Here’s where the other half of TSQ gets set up, and it’s the half that answers the question we left hanging. Remember what it was about: capping how many bytes of one socket can be sitting in the local outbound queues at the same time. Somebody has to keep that count, and this is where it happens. Before sending the skb down, TCP adds its size to that count, and attaches a &lt;strong&gt;destructor&lt;/strong&gt; to it: a function that will run when the skb is freed — which is to say, when the card has actually finished sending it. That function subtracts those bytes again and, if the socket had been throttled for hitting the limit, wakes it up to send more.&lt;/p&gt;&lt;p&gt;So what restarts a throttled socket isn’t a timer, and isn’t anything watching over it: it’s its own packets finishing. TCP transmits &lt;strong&gt;at the rate the card sets&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Past TCP, the packet drops a floor. &lt;code&gt;ip_queue_xmit()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/ip_output.c#L463&quot;&gt;&lt;code&gt;net/ipv4/ip_output.c:463&lt;/code&gt;&lt;/a&gt;) repeats the same move: take the route the socket already had cached, claim a bit more headroom, fill in the IP header.&lt;/p&gt;&lt;p&gt;And here something odd happens: often the packet is deliberately too big for the wire. TCP hands down one oversized skb carrying many packets’ worth of data and lets the card slice it up itself, so the stack gets walked once instead of forty-five times. That’s &lt;strong&gt;segmentation offload&lt;/strong&gt; (&lt;strong&gt;GSO&lt;/strong&gt; in general, &lt;strong&gt;TSO&lt;/strong&gt; when the hardware does it for TCP), and if the card can’t, the kernel does the slicing in software further down.&lt;/p&gt;&lt;p&gt;Finally, &lt;code&gt;ip_finish_output2()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/ipv4/ip_output.c#L200&quot;&gt;&lt;code&gt;net/ipv4/ip_output.c:200&lt;/code&gt;&lt;/a&gt;) turns “next hop 192.168.1.1” into a MAC address, which is what ARP is for. For a neighbour we’ve spoken to recently the whole 14-byte Ethernet header is already cached: it isn’t built, it’s &lt;code&gt;memcpy&lt;/code&gt;’d (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/include/net/neighbour.h#L507&quot;&gt;&lt;code&gt;include/net/neighbour.h:507&lt;/code&gt;&lt;/a&gt;) into the headroom that is &lt;em&gt;still&lt;/em&gt; sitting there from &lt;code&gt;sendmsg&lt;/code&gt;. The packet is complete: Ethernet, IP, TCP, payload.&lt;/p&gt;&lt;p&gt;Nothing has left the machine yet, though. The finished packet still has to make it out to the card.&lt;/p&gt;&lt;h2&gt;Sending to the card&lt;/h2&gt;&lt;p&gt;&lt;code&gt;__dev_queue_xmit()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/dev.c#L4766&quot;&gt;&lt;code&gt;net/core/dev.c:4766&lt;/code&gt;&lt;/a&gt;) is the device layer’s transmit entrance, and it mirrors what we saw on the way in: tc, netfilter and any BPF program attached to the interface get their shot at the packet, with the same power to drop it or send it somewhere else.&lt;/p&gt;&lt;p&gt;Then the packet joins a queue on its way out, and that queue is managed by a &lt;strong&gt;qdisc&lt;/strong&gt; — a &lt;em&gt;queueing discipline&lt;/em&gt;, the scheduler deciding what actually leaves and in what order.&lt;/p&gt;&lt;p&gt;Next, validation. &lt;code&gt;validate_xmit_skb()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/dev.c#L4019&quot;&gt;&lt;code&gt;net/core/dev.c:4019&lt;/code&gt;&lt;/a&gt;) compares what the packet needs against what your card can actually do, and makes up the difference in software: slicing a big skb into wire-sized frames, flattening a payload spread across pages, computing a checksum. This is why the layers above could afford to be so relaxed — they build the packet they &lt;em&gt;want&lt;/em&gt;, and this function reconciles it with whatever hardware you happen to own.&lt;/p&gt;&lt;p&gt;Then the driver. &lt;code&gt;dev_hard_start_xmit()&lt;/code&gt; (&lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/net/core/dev.c#L3894&quot;&gt;&lt;code&gt;net/core/dev.c:3894&lt;/code&gt;&lt;/a&gt;) hands a copy to anything listening to the whole interface — this is where &lt;code&gt;tcpdump&lt;/code&gt; sees &lt;em&gt;outgoing&lt;/em&gt; packets — and then calls into the network device driver.&lt;/p&gt;&lt;p&gt;The driver does the same dance as the receive ring, in reverse (for a real example, Intel’s &lt;code&gt;igb&lt;/code&gt; does it &lt;a href=&quot;https://github.com/torvalds/linux/blob/v7.1/drivers/net/ethernet/intel/igb/igb_main.c#L6273&quot;&gt;here&lt;/a&gt;). The packet’s bytes may be scattered across a few pages, so for each of those pieces the driver asks the kernel for an address the &lt;em&gt;card&lt;/em&gt; can use to reach it, and writes that address into a descriptor. Then it rings the &lt;strong&gt;doorbell&lt;/strong&gt;: the same register write as before, this time saying “descriptors up to here are yours”.&lt;/p&gt;&lt;p&gt;And that’s the last the kernel sees of it. The card reads the descriptors, fetches the bytes, finishes the checksums, and puts frames on the cable.&lt;/p&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;p&gt;Step back from the function names and the journey is fairly simple. A frame lands on the card, which writes it straight into a memory page the kernel handed over long beforehand, and only afterwards mentions that it did. The kernel wraps that page in an skb and passes it upward, each layer asking one question and answering it: is this frame mine, is this packet valid, whose connection is this, and is anybody waiting for these bytes? Somebody was — a thread asleep inside &lt;code&gt;recv()&lt;/code&gt;, which wakes, copies the data out, and returns.&lt;/p&gt;&lt;p&gt;The way back out is the same journey inverted. &lt;code&gt;send()&lt;/code&gt; copies your bytes into a queue and then asks whether anything should go out — a question answered by congestion, the receiver’s window, and how much of its own data is already queued locally. Often the answer is yes and the packet leaves inside the same syscall; when it’s no, the data waits. Then the headers go on backwards, into headroom reserved right at the start, and the driver rings a doorbell.&lt;/p&gt;&lt;p&gt;A few habits repeat throughout. Nothing copies the payload if it can avoid it. Nothing is hardcoded — protocols register themselves in tables rather than turning up in somebody’s switch statement. And nothing travels alone if it can help it, which is what GRO, GSO and the batched doorbell are all quietly doing.&lt;/p&gt;&lt;p&gt;Next time, something completely different: &lt;strong&gt;NUMA&lt;/strong&gt;. On a machine with more than one socket, not all memory is equally close to every CPU, and the kernel has to take that into account both when it allocates memory and when it decides where to run things. We’ll see how it models that, and what it does with it.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Durable AI agent execution beyond terminal sessions · vincent</title>
<link>https://lezli01.is-a.dev/vincent/docs/why/the-terminal-should-not-own-the-work.html</link>
<enclosure type="image/jpeg" length="0" url="https://lezli01.is-a.dev/vincent/docs/assets/social/the-terminal-should-not-own-the-work.png"></enclosure>
<guid isPermaLink="false">FswWXt8FHrj2i-7xTqzPWf9VSXzUhGg-pQKliw==</guid>
<pubDate>Tue, 15 Sep 2026 19:47:47 +0000</pubDate>
<description>Learn how vincent moves coding-agent work out of fragile terminal sessions and into durable tasks that survive disconnects and restarts.</description>
<content:encoded>&lt;h1&gt;The terminal should not own the work&lt;/h1&gt;&lt;p&gt;A terminal is a good place to start a process. It is a poor place to store the
truth about that process.&lt;/p&gt;&lt;p&gt;When an agentic task belongs to one terminal tab, the tab becomes an accidental
control plane. Closing it can stop the work. Losing scrollback can erase the
useful explanation. Reopening the project means reconstructing what ran, which
branch it changed, and whether it was waiting, finished, or quietly stuck. The
longer the task runs, the more fragile that arrangement feels.&lt;/p&gt;&lt;p&gt;Vincent moves ownership into a background daemon. The daemon owns task state,
workflow execution, agent processes, scheduling, the database, and git
worktrees. The TUI, CLI, and API are clients of that state. Closing any client
changes nothing about the work behind it.&lt;/p&gt;&lt;p&gt;That architectural choice has consequences that are easy to feel. I can start a
task, close the TUI, use the terminal for something else, and return later to the
same state and history. Several clients can inspect the same daemon without
becoming competing writers. The scheduler can admit tasks by priority and
concurrency limits even when nobody has a dashboard open.&lt;/p&gt;&lt;p&gt;Durability also changes how interruption is handled. Vincent persists a state
transition before acting on it. If the daemon stops during a step, restart
recovery records the interrupted attempt, verifies any orphaned process before
stopping it, and runs the step again without consuming a failure retry. The
system does not pretend that a process survives a machine restart; it makes the
interruption explicit and recovers from known state.&lt;/p&gt;&lt;p&gt;Installing the daemon as a user service extends the same model across logins.
The operating system starts the control plane, and the terminal returns to being
what it should be: one optional window into the work.&lt;/p&gt;&lt;p&gt;This matters because agentic coding is increasingly a workload rather than a
conversation. Tasks wait on quotas, gates, retries, child branches, and external
checks. Their lifetime should not be coupled to the lifetime of the interface
that launched them.&lt;/p&gt;&lt;p&gt;The terminal can show the work. It should not own the work.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;a href=&quot;https://lezli01.is-a.dev/vincent/docs/why/&quot;&gt;Back to Why vincent is awesome&lt;/a&gt; · &lt;a href=&quot;https://lezli01.is-a.dev/vincent/docs/getting-started/concepts.html#the-daemon&quot;&gt;Understand the daemon&lt;/a&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Finally: Some Pricing Information On The Power S1112 Entry Server</title>
<link>https://www.itjungle.com/2026/09/14/finally-some-pricing-information-on-the-power-s1112-entry-server/</link>
<guid isPermaLink="false">aNttgEIYZ-iwh-02PoIW5pdoRnnp1YR6nXM3pw==</guid>
<pubDate>Tue, 15 Sep 2026 19:05:30 +0000</pubDate>
<description>The entry “Bonnell+” Power S1112 server based on the Power11 processor – the only machine that has a P05 software tier for the IBM i operating system – has been shipping for six weeks now, and I have been digging around trying to get detailed, feature-level pricing for the new machine. I have yet to find that fine-grained pricing that I love to have my hands on, but I did get some help from some friends in the reseller community to get current prices for six different configurations o...</description>
<content:encoded>&lt;p&gt;The entry “Bonnell+” Power S1112 server based on the Power11 processor – the only machine that has a P05 software tier for the IBM i operating system – has been shipping for six weeks now, and I have been digging around trying to get detailed, feature-level pricing for the new machine. I have yet to find that fine-grained pricing that I love to have my hands on, but I did get some help from some friends in the reseller community to get current prices for six different configurations of the Power S1112 – two tower configurations and four rack configurations. &lt;a href=&quot;https://www.itjungle.com/2026/09/14/finally-some-pricing-information-on-the-power-s1112-entry-server/&quot;&gt;… &lt;/a&gt;&lt;/p&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.itjungle.com/2026/09/14/finally-some-pricing-information-on-the-power-s1112-entry-server/&quot;&gt;Finally: Some Pricing Information On The Power S1112 Entry Server&lt;/a&gt; appeared first on IT Jungle.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Any Nix package, live in your browser</title>
<link>https://simonwillison.net/2026/Sep/10/trynix/</link>
<guid isPermaLink="false">f3C0BtRVY-uFPGjfXJDUPb2dFHjhCEX1t2fhdw==</guid>
<pubDate>Tue, 15 Sep 2026 12:08:27 +0000</pubDate>
<description>Any Nix package, live in your browser Farid Zakaria calls this his &quot;magnum opus of Nix work&quot;, and I can see why.trynix.dev provides a qemu-wasm powered x86_64 Linux virtual machine running entirely in your browser through WebAssembly. That VM can then be booted with any Nix package from the past 13 years. They are URL addressable, so you can navigate to this page: https://trynix.dev/?pkg=python3%403.6.2 Then click &quot;Load&quot; and get an interactive shell against a virtual machine running Python 3....</description>
<content:encoded>&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://fzakaria.com/2026/09/04/any-nix-package-live-in-your-browser&quot;&gt;Any Nix package, live in your browser&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt; Farid Zakaria calls this his &amp;quot;&lt;em&gt;magnum opus&lt;/em&gt; of Nix work&amp;quot;, and I can see why.&lt;p&gt;trynix.dev provides a &lt;a href=&quot;https://github.com/ktock/qemu-wasm&quot;&gt;qemu-wasm&lt;/a&gt; powered x86_64 Linux virtual machine running entirely in your browser through WebAssembly. That VM can then be booted with &lt;em&gt;any Nix package&lt;/em&gt; from the past 13 years. They are URL addressable, so you can navigate to this page:&lt;/p&gt;&lt;p&gt;https://trynix.dev/?pkg=python3%403.6.2&lt;/p&gt;&lt;p&gt;Then click &amp;quot;Load&amp;quot; and get an interactive shell against a virtual machine running Python 3.6.2 from 2017.&lt;/p&gt;&lt;p&gt;Farid is building all sorts of neat things on top of this. One recent example: &lt;a href=&quot;https://fzakaria.com/2026/09/09/review-a-pull-request-by-booting-it&quot;&gt;Review a pull request by booting it&lt;/a&gt; introduces &lt;a href=&quot;https://github.com/marketplace/actions/trynix-preview&quot;&gt;trynix-preview&lt;/a&gt;, described like this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;GitHub action that comments a link on a pull request which lets you boot the PR’s build in the browser using https://trynix.dev. No servers, just browsers.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Via &lt;a href=&quot;https://lobste.rs/s/7lii0g/review_pull_request_by_booting_it&quot;&gt;Lobste.rs&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Tags: &lt;a href=&quot;https://simonwillison.net/tags/code-review&quot;&gt;code-review&lt;/a&gt;, &lt;a href=&quot;https://simonwillison.net/tags/linux&quot;&gt;linux&lt;/a&gt;, &lt;a href=&quot;https://simonwillison.net/tags/webassembly&quot;&gt;webassembly&lt;/a&gt;, &lt;a href=&quot;https://simonwillison.net/tags/github-actions&quot;&gt;github-actions&lt;/a&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Dropping eBPF CPU Cost by About 90% With Memoization (Not AI Gen) :: nathan naveen</title>
<link>https://nathannaveen.dev/posts/dropping-ebpf-cpu-cost-by-90/</link>
<enclosure type="image/jpeg" length="0" url="https://nathannaveen.dev/"></enclosure>
<guid isPermaLink="false">GhTPK5bPzybx9XwdaF6Sbf0ryk5PVSz9rm2zRQ==</guid>
<pubDate>Tue, 15 Sep 2026 04:41:46 +0000</pubDate>
<description>My brother and I spent a lot of time designing our eBPF security agent to be really fast from the ground up, but recently we discovered we could make it much faster using memoization! A couple of weeks ago, I profiled the eBPF code and found that the most expensive part of the protection isn’t actually enforcing a policy (allow/deny), but figuring out which policy applies to a given file open.</description>
<content:encoded>&lt;p&gt;My brother and I spent a lot of time designing our eBPF security agent to be really fast from the ground up, but recently we discovered we could make it much faster using memoization!&lt;/p&gt;&lt;p&gt;A couple of weeks ago, I profiled the eBPF code and found that the most expensive part of the protection isn’t actually enforcing a policy (allow/deny), but figuring out which policy applies to a given file open.&lt;/p&gt;&lt;p&gt;Our policies are path based, so our eBPF leverages an LSM hook that triggers on file open. We then reconstruct the path, walk up parent dentries, and check whether the file or any ancestor directory has a matching policy. While this works, it isn’t performant, and we end up repeating much of the work for files we have already seen (for example, database accesses that repeatedly reaccess file paths).&lt;/p&gt;&lt;p&gt;So, we cache which policy applies for each inode. This dropped our kernel CPU cost by about 90%.&lt;/p&gt;&lt;p&gt;Additionally, we recently open sourced our repo, so everything in this blog post can be found at &lt;a href=&quot;https://github.com/bomfather/agent&quot;&gt;https://github.com/bomfather/agent&lt;/a&gt;.&lt;/p&gt;&lt;h1&gt;The Problem&lt;/h1&gt;&lt;p&gt;Before the cache, every file open would walk through the entire path. So the flow would look like this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Get the file path.&lt;/li&gt;&lt;li&gt;Walk up the file path with dentries.&lt;/li&gt;&lt;li&gt;At each level, check whether a policy exists for the path.&lt;/li&gt;&lt;li&gt;Then combine the results to get a final policy, which we can use to decide whether to allow or deny.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This works, but if the same file is opened multiple times or multiple files in the same subtree are opened, we have to repeat these steps for each file.&lt;/p&gt;&lt;p&gt;For example: In Postgres, if we only want Postgres to be able to touch &lt;code&gt;/var/lib/postgres&lt;/code&gt;, we can have this example policy:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;policies:
  - executable: &amp;quot;filepath = /usr/lib/postgresql/16/bin/postgres&amp;quot;
    can_access_dirs:
      - &amp;quot;/var/lib/postgres:read&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then Postgres retrieves files from &lt;code&gt;var/lib/postgres/data/base/123&lt;/code&gt;, &lt;code&gt;var/lib/postgres/data/base/234&lt;/code&gt;, and &lt;code&gt;var/lib/postgres/data/base/345&lt;/code&gt;. We would have to walk the entire path of dentries for each of these file accesses, which is really inefficient.&lt;/p&gt;&lt;p&gt;For the rest of this blog post, I’ll call this inefficient path walk “the slow path.”&lt;/p&gt;&lt;h1&gt;What’s in the Cache?&lt;/h1&gt;&lt;p&gt;Our solution is to use a cache. But we need to make sure the cache isn’t heavy and that it’s safe to reuse cached items.&lt;/p&gt;&lt;p&gt;We were thinking of using dentries, but dentries are pointers, and pointers can’t be stored inside eBPF maps. If we wanted to use dentries, we could store the dentries’ contents in a struct and use that struct as the map key, but it would be a pretty heavy struct.&lt;/p&gt;&lt;p&gt;So instead, we decided to use an &lt;code&gt;inode&lt;/code&gt; based cache. Our cache key has three fields: the mount namespace ID, the mount ID, and the inode number.&lt;/p&gt;&lt;p&gt;We can’t cache the &lt;code&gt;inode&lt;/code&gt; by itself because inode numbers are unique to a specific mount tree (so if a policy covers multiple mount trees, inodes could overlap). The mount ID helps us identify which mounted tree we observed the file through. The mount namespace ID also prevents us from using cached entries in a different namespace.&lt;/p&gt;&lt;p&gt;The cache value has two parts: an &lt;code&gt;access_index&lt;/code&gt; and a cache state. We store our policies as bitmasks for space efficiency, and the &lt;code&gt;access_index&lt;/code&gt; is the bit position for the path policy (&lt;a href=&quot;https://nathannaveen.dev/posts/optimizing-ebpf-policies-for-speed-and-space/%29&quot;&gt;https://nathannaveen.dev/posts/optimizing-ebpf-policies-for-speed-and-space/)&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;So, our cache, along with the keys and values, looks something like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define INODE_POLICY_CACHE_NO_POLICY 0
#define INODE_POLICY_CACHE_ACCESS_INDEX 1
#define INODE_POLICY_CACHE_GLOBAL_READ_ONLY 2
#define INODE_POLICY_CACHE_ACCESS_INDEX_AND_GLOBAL_RO 3 

struct inode_cache_key {
    u64 mntns_id;
    u64 mount_id;
    u64 inode;
};

struct inode_policy_cache_value {
    u32 access_index;
    u8 state;
};

struct {
    __uint(type, BPF_MAP_TYPE_LRU_HASH);
    __uint(max_entries, 10000);
    __type(key, struct inode_cache_key);
    __type(value, struct inode_policy_cache_value);
} bomfather_inode_policy_cache SEC(&amp;quot;.maps&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now with the cache, our flow looks something like this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We need to build the cache key.&lt;/li&gt;&lt;li&gt;We can look up the key in the LRU hash map.&lt;/li&gt;&lt;li&gt;If there is a hit, we can enforce the file open based on the cached result.&lt;/li&gt;&lt;li&gt;If there is a miss, we can do the slow path and store the result in the cache.&lt;/li&gt;&lt;/ol&gt;&lt;img src=&quot;https://nathannaveen.dev/img/BMBlogDiagram.jpeg&quot; alt=&quot;On a cache hit, file open builds an inode cache key and goes straight to allow or deny. On a miss, it walks parent dentries, merges the policy, stores the result, then allows or denies.&quot; title=&quot;&quot;/&gt;&lt;h1&gt;Performance Changes&lt;/h1&gt;&lt;p&gt;In our benchmark tests, we opened the same file 200,000 times to analyze performance; the cache reduced kernel cycles from 28 billion to 3.03 billion. Without the cache, our &lt;code&gt;tail_call_security_check&lt;/code&gt; appeared on the stack 89.2%, &lt;code&gt;is_restricted_filepath&lt;/code&gt; 81.9%, and &lt;code&gt;path_check_callback&lt;/code&gt; 63.7% of the time.&lt;/p&gt;&lt;p&gt;In the flamegraphs below, we can see that with the cache, the expense from path traversal pretty much disappears after the first lookup. For example, &lt;code&gt;is_restricted_filepath&lt;/code&gt; and &lt;code&gt;path_check_callback&lt;/code&gt; each shrink to roughly 0.02%, which is small enough to effectively disappear from the graph.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Before (without cache):&lt;/strong&gt;&lt;/p&gt;&lt;img src=&quot;https://nathannaveen.dev/img/kernel-flamegraph-no-cache-annotated.svg&quot; alt=&quot;Kernel flamegraph without the inode cache, with tail_call_security_check, is_restricted_filepath, and path_check_callback dominating the stack.&quot; title=&quot;&quot;/&gt;&lt;p&gt;&lt;strong&gt;After (with cache):&lt;/strong&gt;&lt;/p&gt;&lt;img src=&quot;https://nathannaveen.dev/img/kernel-flamegraph-cache-annotated.svg&quot; alt=&quot;Kernel flamegraph with the inode cache, where path traversal cost has mostly disappeared after the first lookup.&quot; title=&quot;&quot;/&gt;&lt;p&gt;We profiled the kernel CPU with &lt;code&gt;perf&lt;/code&gt; using the &lt;code&gt;cycles:k&lt;/code&gt; event. This measures kernel side CPU cost during file opens.&lt;/p&gt;&lt;h1&gt;Edge Cases&lt;/h1&gt;&lt;p&gt;One thing we had to account for with this cache is that multiple paths can share a single inode. Hardlinks are the easiest example; with a hardlink, two different paths can share the same inode. This is a big problem because accurate results matter more than cache performance.&lt;/p&gt;&lt;p&gt;Our solution is more of a workaround than a real solution. Inodes have a link count (&lt;code&gt;i_nlink&lt;/code&gt;) that tells us how many paths point to the inode; we can read it, and if it is greater than 1, we don’t use that cache entry and fall back to the slow path.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;if (BPF_CORE_READ_INTO(&amp;amp;nlink, inode, i_nlink)) {
    return false;
}

if (nlink != 1) {
    inode_cache_stats_inc(INODE_CACHE_STATS_SKIPS_NLINK);
    return false;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a trade off since we are giving up some cache coverage, but I don’t think it is too big a deal because having an accurate cache is most important.&lt;/p&gt;&lt;h1&gt;Final Thoughts&lt;/h1&gt;&lt;p&gt;In the end, this was a really fun thing to work on since I had to work through multiple different ideas for the cache until I landed on this.&lt;/p&gt;&lt;p&gt;I am also pretty happy the cache is entirely internal, so a user’s policy doesn’t need to change for the agent to speed up!&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Setting up CachyOS on a ThinkPad T14s Gen 1 AMD with LUKS2, BTRFS, Limine and Sway</title>
<link>https://blog.zm.is/setting-up-cachyos-on-a-thinkpad-t14s-gen-1-amd-with-luks2-btrfs-limine-and-sway/</link>
<enclosure type="image/jpeg" length="0" url="https://blog.zm.is/content/images/2026/05/signal-2026-05-19-19-35-34-243.jpg"></enclosure>
<guid isPermaLink="false">rKRAnDjEOQIc7U5KO9gblDjokuLdS35FuJC85w==</guid>
<pubDate>Mon, 14 Sep 2026 17:44:13 +0000</pubDate>
<description>I wanted a boring laptop. Not boring in the “old corporate machine with a dying battery” sense, although this is a ThinkPad, so there is always a bit of that. I mean boring in the useful sense: encrypted, recoverable, fast enough, boring to boot, boring to update, boring to suspend,</description>
<content:encoded>&lt;p&gt;I wanted a boring laptop.&lt;/p&gt;&lt;p&gt;Not boring in the “old corporate machine with a dying battery” sense, although this is a ThinkPad, so there is always a bit of that. I mean boring in the useful sense: encrypted, recoverable, fast enough, boring to boot, boring to update, boring to suspend, and boring enough that I can stop thinking about the machine and start building things on it.&lt;/p&gt;&lt;p&gt;Naturally, this meant wiping the disk more than once.&lt;/p&gt;&lt;p&gt;This is a guide to setting up CachyOS on a ThinkPad T14s Gen 1 AMD with LUKS2, Btrfs subvolumes, a Btrfs swapfile for hibernation, Limine, Snapper, AppArmor, Sway, and Ly with the cmatrix animation, because if you are going to use a terminal display manager you may as well make it look slightly ridiculous.&lt;/p&gt;&lt;p&gt;This is based on the actual install I did, not the imaginary blog-post version where every decision was obvious before I typed the first command. The final setup worked out nicely, but I did change direction during the install. The original plan was a simpler encrypted setup. Then I looked more closely at the CachyOS Btrfs/Limine/Snapper path and decided it was worth doing properly.&lt;/p&gt;&lt;h2&gt;The hardware&lt;/h2&gt;&lt;p&gt;The machine is a ThinkPad T14s Gen 1 AMD:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ThinkPad T14s Gen 1
Ryzen 7 PRO 4750U
14 GiB usable RAM
WDC PC SN730 476.9G NVMe SSD&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The final stack:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;CachyOS
4 GiB EFI System Partition
LUKS2 encrypted root
Btrfs with CachyOS-style subvolumes
24 GiB Btrfs swapfile for hibernation
Limine bootloader
Snapper snapshots via limine-snapper-sync
AppArmor
Sway Wayland desktop
Ly display manager with cmatrix animation&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is not the absolute simplest Linux laptop install. If you just want something that boots, use the normal CachyOS installer and get on with your day. This guide is for the slightly more annoying case: a manual install with encrypted root, snapshot-friendly Btrfs, hibernation, and a minimal Wayland desktop.&lt;/p&gt;&lt;h2&gt;Before you copy anything&lt;/h2&gt;&lt;p&gt;This guide wipes the internal NVMe drive. In my case, the target disk was &lt;code&gt;/dev/nvme0n1&lt;/code&gt;. Yours may not be. Check before running destructive commands.&lt;/p&gt;&lt;p&gt;If you copy and paste the partitioning commands without checking your disk names, you may have a very efficient data deletion experience.&lt;/p&gt;&lt;p&gt;Most commands are run from the CachyOS live ISO. Some commands require interactive passphrase entry and should be run directly on the laptop. I did some of the install over SSH using &lt;code&gt;ssh cachy&lt;/code&gt;, but I have written the commands below as if you are typing them directly on the live system.&lt;/p&gt;&lt;h2&gt;1. Verify the environment&lt;/h2&gt;&lt;p&gt;Start by confirming the target disk and that you booted the installer in UEFI mode.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lsblk -o NAME,PATH,MODEL,SERIAL,SIZE,TYPE,FSTYPE,LABEL,MOUNTPOINTS
ls -d /sys/firmware/efi/efivars&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Expected: the internal disk is &lt;code&gt;/dev/nvme0n1&lt;/code&gt;, and &lt;code&gt;/sys/firmware/efi/efivars&lt;/code&gt; exists. If you do not see EFI variables, stop and fix your boot mode before continuing.&lt;/p&gt;&lt;h2&gt;2. Partition the disk&lt;/h2&gt;&lt;p&gt;I ended up using a 4 GiB EFI System Partition because this setup uses Limine with snapshot boot support. The rest of the disk becomes one LUKS2 container.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sgdisk --zap-all /dev/nvme0n1

sgdisk \
  -n 1:1MiB:+4GiB -t 1:ef00 -c 1:EFI \
  -n 2:0:0        -t 2:8309 -c 2:cryptroot \
  /dev/nvme0n1

partprobe /dev/nvme0n1
lsblk -o NAME,PATH,SIZE,TYPE,PARTTYPENAME,PARTLABEL /dev/nvme0n1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Format the ESP:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.fat -F32 -n EFI /dev/nvme0n1p1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At this point, &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt; is the EFI partition and &lt;code&gt;/dev/nvme0n1p2&lt;/code&gt; is the partition that will hold the encrypted root.&lt;/p&gt;&lt;h2&gt;3. Create and open the LUKS2 container&lt;/h2&gt;&lt;p&gt;Run this directly on the laptop. It requires typing &lt;code&gt;YES&lt;/code&gt; and entering the encryption passphrase.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cryptsetup luksFormat \
  --type luks2 \
  --cipher aes-xts-plain64 \
  --key-size 512 \
  --hash sha512 \
  --pbkdf argon2id \
  --label cryptroot \
  /dev/nvme0n1p2

cryptsetup open /dev/nvme0n1p2 cryptroot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Verify the mapper exists:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,LABEL /dev/nvme0n1 /dev/mapper/cryptroot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should see &lt;code&gt;/dev/nvme0n1p2&lt;/code&gt; as &lt;code&gt;crypto_LUKS&lt;/code&gt; and &lt;code&gt;/dev/mapper/cryptroot&lt;/code&gt; as the opened encrypted device.&lt;/p&gt;&lt;h2&gt;4. Create the Btrfs filesystem&lt;/h2&gt;&lt;p&gt;Create the filesystem inside the opened LUKS container:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.btrfs -L cachyos /dev/mapper/cryptroot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then create the subvolume layout. This is the CachyOS-style layout, with extra subvolumes for snapshots and swap.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mount /dev/mapper/cryptroot /mnt

btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@root
btrfs subvolume create /mnt/@srv
btrfs subvolume create /mnt/@cache
btrfs subvolume create /mnt/@tmp
btrfs subvolume create /mnt/@log
btrfs subvolume create /mnt/@snapshots
btrfs subvolume create /mnt/@swap

btrfs subvolume list /mnt
umount /mnt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Btrfs snapshots are not backups. They are rollback points. If an update breaks the system, a snapshot can get you back to a working state quickly. It will not save you from disk failure, theft, or deleting something and only noticing six months later.&lt;/p&gt;&lt;p&gt;Use snapshots for recovery. Use backups for backups.&lt;/p&gt;&lt;h2&gt;5. Mount everything for installation&lt;/h2&gt;&lt;p&gt;Mount the root subvolume first:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mount -o subvol=@,compress=zstd:3,noatime,ssd,discard=async \
  /dev/mapper/cryptroot /mnt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create the mountpoint directories:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p /mnt/{boot,home,root,srv,.snapshots,swap}
mkdir -p /mnt/var/{cache,tmp,log}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mount the remaining subvolumes:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;OPTS=&amp;quot;compress=zstd:3,noatime,ssd,discard=async&amp;quot;

mount -o subvol=@home,$OPTS      /dev/mapper/cryptroot /mnt/home
mount -o subvol=@root,$OPTS      /dev/mapper/cryptroot /mnt/root
mount -o subvol=@srv,$OPTS       /dev/mapper/cryptroot /mnt/srv
mount -o subvol=@cache,$OPTS     /dev/mapper/cryptroot /mnt/var/cache
mount -o subvol=@tmp,$OPTS       /dev/mapper/cryptroot /mnt/var/tmp
mount -o subvol=@log,$OPTS       /dev/mapper/cryptroot /mnt/var/log
mount -o subvol=@snapshots,$OPTS /dev/mapper/cryptroot /mnt/.snapshots
mount -o subvol=@swap,$OPTS      /dev/mapper/cryptroot /mnt/swap&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mount the ESP:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mount /dev/nvme0n1p1 /mnt/boot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check the whole mount tree:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;findmnt -R /mnt&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;6. Create a Btrfs swapfile for hibernation&lt;/h2&gt;&lt;p&gt;The laptop has 14 GiB usable RAM, so I used a 24 GiB swapfile to support hibernation.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;btrfs filesystem mkswapfile --size 24g /mnt/swap/swapfile
swapon /mnt/swap/swapfile&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Collect the resume offset and UUIDs. You will need these later for the kernel command line.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;btrfs inspect-internal map-swapfile -r /mnt/swap/swapfile   # resume offset
blkid -s UUID -o value /dev/nvme0n1p2                       # LUKS UUID
blkid -s UUID -o value /dev/mapper/cryptroot                # Btrfs UUID
blkid -s UUID -o value /dev/nvme0n1p1                       # EFI UUID&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Write them down somewhere that is not the terminal scrollback you are about to lose.&lt;/p&gt;&lt;h2&gt;7. Install the base system&lt;/h2&gt;&lt;p&gt;Install the base CachyOS system and the bits needed for encrypted boot, Btrfs, Limine, Snapper, networking, and AppArmor.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pacstrap /mnt base linux-cachyos linux-cachyos-headers linux-firmware amd-ucode \
  btrfs-progs cryptsetup mkinitcpio networkmanager sudo vim nano \
  man-db man-pages texinfo bash-completion dosfstools e2fsprogs efibootmgr \
  limine limine-mkinitcpio-hook limine-snapper-sync snapper \
  cachyos-keyring cachyos-mirrorlist cachyos-settings cachyos-hooks chwd \
  apparmor hunspell-en_gb inetutils which&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Generate &lt;code&gt;fstab&lt;/code&gt; and fix a couple of permissions:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;genfstab -U /mnt | tee -a /mnt/etc/fstab
chmod 750 /mnt/root
chmod 1777 /mnt/var/tmp&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;/var/tmp&lt;/code&gt; needs to be world-writable and sticky. Forgetting this is a very boring way to create very annoying problems later.&lt;/p&gt;&lt;h2&gt;8. Configure encrypted boot&lt;/h2&gt;&lt;p&gt;Use a systemd-based initramfs with &lt;code&gt;sd-encrypt&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sed -i &amp;#39;s/^HOOKS=.*/HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)/&amp;#39; /mnt/etc/mkinitcpio.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now write the kernel command line. Substitute your own LUKS UUID, Btrfs UUID, and resume offset.&lt;/p&gt;&lt;p&gt;I included &lt;code&gt;psmouse.elantech_smbus=1&lt;/code&gt; because the TrackPoint on this AMD ThinkPad involves the Elan SMBus companion path. Whether it saves you is another matter, but at least it shows where the bodies are buried.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p /mnt/etc/kernel

cat &amp;gt; /mnt/etc/kernel/cmdline &amp;lt;&amp;lt;EOF
psmouse.elantech_smbus=1 rd.luks.name=&amp;lt;LUKS_UUID&amp;gt;=cryptroot root=UUID=&amp;lt;BTRFS_UUID&amp;gt; rootflags=subvol=@ rw resume=UUID=&amp;lt;BTRFS_UUID&amp;gt; resume_offset=&amp;lt;OFFSET&amp;gt; apparmor=1 security=apparmor lsm=landlock,lockdown,yama,integrity,apparmor,bpf
EOF&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Regenerate initramfs and update Limine:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt mkinitcpio -P
arch-chroot /mnt limine-update
grep cmdline /mnt/boot/limine.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You want to see your LUKS, root, resume, and AppArmor parameters in the generated Limine config.&lt;/p&gt;&lt;h2&gt;9. Enable core services&lt;/h2&gt;&lt;p&gt;Enable AppArmor and NetworkManager:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt systemctl enable apparmor.service
arch-chroot /mnt systemctl enable NetworkManager.service&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;10. Set hostname, locale and timezone&lt;/h2&gt;&lt;p&gt;I called the machine &lt;code&gt;bc&lt;/code&gt;. Use whatever hostname you want.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo bc &amp;gt; /mnt/etc/hostname
printf &amp;#39;%s\n&amp;#39; &amp;#39;127.0.0.1 localhost&amp;#39; &amp;#39;::1 localhost&amp;#39; &amp;#39;127.0.1.1 bc.localdomain bc&amp;#39; &amp;gt; /mnt/etc/hosts&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Set locale and keyboard:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sed -i &amp;#39;s/^#en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/; s/^#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/&amp;#39; /mnt/etc/locale.gen
arch-chroot /mnt locale-gen
echo LANG=en_GB.UTF-8 &amp;gt; /mnt/etc/locale.conf
echo KEYMAP=uk &amp;gt; /mnt/etc/vconsole.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Set timezone:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/London /etc/localtime
arch-chroot /mnt hwclock --systohc&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;11. Create the user&lt;/h2&gt;&lt;p&gt;Create the user and allow the wheel group to use sudo without a password. I used &lt;code&gt;x&lt;/code&gt; as the username on this machine.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt useradd -m -G wheel,seat,video,audio,input,storage -s /bin/bash x

echo &amp;#39;%wheel ALL=(ALL:ALL) NOPASSWD: ALL&amp;#39; &amp;gt; /mnt/etc/sudoers.d/00-wheel
chmod 440 /mnt/etc/sudoers.d/00-wheel&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Set passwords:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt passwd x
arch-chroot /mnt passwd root&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you plan to use fingerprint sudo later, remember that &lt;code&gt;NOPASSWD&lt;/code&gt; means sudo will not prompt at all, so fingerprint auth will not appear. That is for the next post. First we need a machine that boots.&lt;/p&gt;&lt;h2&gt;12. Configure root SSH key access&lt;/h2&gt;&lt;p&gt;I wanted key-based root SSH access for setup and recovery. Add your own public key.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;install -d -m 700 /mnt/root/.ssh
echo &amp;#39;&amp;lt;YOUR_SSH_PUBKEY&amp;gt;&amp;#39; &amp;gt; /mnt/root/.ssh/authorized_keys
chmod 600 /mnt/root/.ssh/authorized_keys&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Configure sshd:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;install -d /mnt/etc/ssh/sshd_config.d
cat &amp;gt; /mnt/etc/ssh/sshd_config.d/10-root-login.conf &amp;lt;&amp;lt;EOF
PermitRootLogin prohibit-password
PasswordAuthentication yes
PubkeyAuthentication yes
EOF&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Generate host keys and enable sshd:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt ssh-keygen -A
arch-chroot /mnt systemctl enable sshd.service&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yes, &lt;code&gt;PasswordAuthentication yes&lt;/code&gt; looks funny next to root key-only access. &lt;code&gt;PermitRootLogin prohibit-password&lt;/code&gt; prevents root password login specifically. You can tighten this further once the machine is up and you are no longer balancing on the branch you are sawing.&lt;/p&gt;&lt;h2&gt;13. Install Sway and basic desktop packages&lt;/h2&gt;&lt;p&gt;Install a small Sway desktop, audio, clipboard, screenshots, fonts, Firefox, Evolution, and Ly.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pacstrap /mnt \
  sway swaybg swayidle swaylock xorg-xwayland \
  xdg-desktop-portal-wlr xdg-desktop-portal-gtk \
  kitty foot rofi waybar \
  pipewire pipewire-pulse wireplumber pavucontrol \
  brightnessctl grim slurp wl-clipboard mako \
  pcmanfm mousepad firefox evolution \
  ly cmatrix \
  ttf-iosevka-nerd ttf-iosevkaterm-nerd noto-fonts noto-fonts-emoji \
  polkit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I originally had &lt;code&gt;nm-applet&lt;/code&gt; in mind, but that uses legacy XEmbed and does not work properly in Sway. Use &lt;code&gt;nm-tray&lt;/code&gt; later instead:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;paru -S nm-tray&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is a post-boot polish item, not something worth blocking the install on.&lt;/p&gt;&lt;h2&gt;14. Configure Ly with cmatrix&lt;/h2&gt;&lt;p&gt;Ly uses a template unit. I enabled it on &lt;code&gt;tty2&lt;/code&gt; and disabled the conflicting getty.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;arch-chroot /mnt systemctl disable [email protected]
arch-chroot /mnt systemctl enable [email protected]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Enable the matrix animation:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sed -i &amp;#39;s/^animation = .*/animation = matrix/&amp;#39; /mnt/etc/ly/config.ini&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On boot, Ly presents a terminal login on &lt;code&gt;tty2&lt;/code&gt; with falling green characters. After login, it launches the user’s Sway session from:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/usr/share/wayland-sessions/sway.desktop&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Is this necessary? No. Is it the correct amount of stupid for a ThinkPad running an encrypted manual CachyOS install? Obviously.&lt;/p&gt;&lt;h2&gt;15. Reboot&lt;/h2&gt;&lt;p&gt;Unmount everything and close the encrypted root:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;umount -R /mnt
cryptsetup close cryptroot
reboot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After reboot, unlock LUKS and log in through Ly. Then verify the basics:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;swaymsg -t get_inputs
sudo snapper list
sudo aa-status
efibootmgr -v | grep Limine
free -h&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At this point the machine has a working encrypted CachyOS install with Btrfs subvolumes, Limine boot, Snapper snapshot support, AppArmor enabled, Sway installed, and a terminal login screen that looks like it escaped from a 1999 hacker film.&lt;/p&gt;&lt;p&gt;That is enough for the base laptop setup post. The machine boots, unlocks, logs in, and has a usable Wayland environment.&lt;/p&gt;&lt;p&gt;The next layer is the personal workstation stuff: dotfiles, GPG, YubiKey, smart card behaviour, SSH agent forwarding, fingerprint sudo, and the small collection of problems that appear once a laptop stops being a fresh install and starts being an actual working machine.&lt;/p&gt;&lt;h2&gt;Known issues from this install&lt;/h2&gt;&lt;p&gt;The TrackPoint and physical buttons were not fully happy. The Elantech v4 SMBus companion on this AMD Renoir ThinkPad did not initialise cleanly, with the familiar “SMBus companion is not ready yet” class of failure. The workaround for now is touchpad tap-to-click.&lt;/p&gt;&lt;p&gt;&lt;code&gt;fwupd&lt;/code&gt; also needed attention because Limine and the ESP location can confuse ESP detection. If firmware updates matter to you, check this before assuming capsule updates will just work.&lt;/p&gt;&lt;p&gt;Finally, &lt;code&gt;nm-applet&lt;/code&gt; is not the right tray tool for Sway. Use &lt;code&gt;nm-tray&lt;/code&gt; instead.&lt;/p&gt;&lt;h2&gt;Reference values from my install&lt;/h2&gt;&lt;p&gt;Do not copy these blindly. They are here to show what the real output looked like.&lt;/p&gt;&lt;p&gt;Kernel command line, with shortened UUIDs:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;psmouse.elantech_smbus=1 rd.luks.name=b5290f64-...=cryptroot root=UUID=b66eba1e-... rootflags=subvol=@ rw resume=UUID=b66eba1e-... resume_offset=533760 apparmor=1 security=apparmor lsm=landlock,lockdown,yama,integrity,apparmor,bpf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There we have it. A fast, encrypted CachyOS laptop with snapshots, hibernation, Sway, and just enough green terminal nonsense to remind you why you liked Linux in the first place.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>How to Sandbox a Linux Process with Landlock, No Root Required</title>
<link>https://www.freecodecamp.org/news/how-to-sandbox-a-linux-process-with-landlock-no-root-required/</link>
<guid isPermaLink="false">VaUcrkYTheMGlAYHTD6JEUDs3i66HY75hLMztQ==</guid>
<pubDate>Mon, 14 Sep 2026 17:00:08 +0000</pubDate>
<description>Here&#39;s a program restricting itself, then trying to read two files: without landlock: read /etc/hostname ok read /tmp/secret.txt ok with landlock, /etc allowed: read</description>
<content:encoded>&lt;p&gt;Here&amp;#39;s a program restricting itself, then trying to read two files:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;without landlock:
  read /etc/hostname            ok
  read /tmp/secret.txt          ok
with landlock, /etc allowed:
  read /etc/hostname            ok
  read /tmp/secret.txt          FAILED (Permission denied)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;#39;s no root, no container, no configuration file, and no daemon. The program asked the kernel to take away its own access to most of the filesystem, and the kernel obliged.&lt;/p&gt;&lt;p&gt;That&amp;#39;s Landlock, which has been in the kernel since 2021 without most people noticing. This article builds that program from nothing, runs it, and then walks into the four surprises that catch people the first time.&lt;/p&gt;&lt;h2&gt;Table of Contents&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;What You Need&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Where Landlock Sits&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Three System Calls and No Library&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;A Program That Restricts Itself&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Why &lt;code&gt;no_new_privs&lt;/code&gt; is Mandatory&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Rulesets Intersect, They Never Widen&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;What Your Children Inherit&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;exec&lt;/code&gt; Trap&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Wrapping a Program You Didn&amp;#39;t Write&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Finding the Paths a Program Needs&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Which ABI Version You Have&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Conclusion&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Epilogue&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;What You Need&lt;/h2&gt;&lt;p&gt;To follow along, you&amp;#39;ll need a kernel of 5.13 or newer, the standard headers, and a C compiler. Nothing else, and notably not root.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;grep landlock /sys/kernel/security/lsm
ls /usr/include/linux/landlock.h&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first command matters. Landlock can be compiled into a kernel and still be inactive, because Linux Security Modules have to be enabled at boot. On this machine, that file reads &lt;code&gt;lockdown,capability,landlock,yama,apparmor&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;If &lt;code&gt;landlock&lt;/code&gt; is missing from yours, add &lt;code&gt;lsm=landlock,&lt;/code&gt; to the front of the existing list in your kernel command line and reboot. Ubuntu has shipped it enabled since 22.04, and current Fedora and Arch kernels carry it too, but the &lt;code&gt;grep&lt;/code&gt; above is the only answer that counts for your machine.&lt;/p&gt;&lt;p&gt;Everything below was run on kernel 5.15.0-190-generic under Ubuntu 22.04.5, compiled with gcc 11.4, as an ordinary user with no sudo anywhere.&lt;/p&gt;&lt;h2&gt;Where Landlock Sits&lt;/h2&gt;&lt;p&gt;Linux Security Modules are a framework, not a policy. The kernel calls out to LSM hooks at decision points, before opening a file, creating a process, or mapping executable memory, and whatever modules are loaded get to say yes or no.&lt;/p&gt;&lt;p&gt;SELinux and AppArmor are the two most people have heard of, and both are administrator tools: someone with root writes a policy, the system loads it, and your program lives inside whatever that policy says.&lt;/p&gt;&lt;p&gt;Landlock inverts that. It&amp;#39;s the first LSM a process can apply to itself, without privilege, at runtime. You don&amp;#39;t need to convince an administrator that your program deserves a policy. The program asks for less than it currently has, and the kernel narrows it.&lt;/p&gt;&lt;p&gt;That &amp;quot;asks for less&amp;quot; is the whole design. Landlock can only ever remove access. There&amp;#39;s no call that grants you something you didn&amp;#39;t already have, which is precisely why it&amp;#39;s safe to expose to unprivileged processes.&lt;/p&gt;&lt;h2&gt;Three System Calls and No Library&lt;/h2&gt;&lt;p&gt;Landlock is three syscalls and glibc wraps none of them, so you call them directly through &lt;code&gt;syscall()&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;static int create_ruleset(const struct landlock_ruleset_attr *attr)
{ return syscall(__NR_landlock_create_ruleset, attr, sizeof(*attr), 0); }

static int add_rule(int fd, const struct landlock_path_beneath_attr *pb)
{ return syscall(__NR_landlock_add_rule, fd, LANDLOCK_RULE_PATH_BENEATH, pb, 0); }

static int restrict_self(int fd)
{ return syscall(__NR_landlock_restrict_self, fd, 0); }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;landlock_create_ruleset&lt;/code&gt; declares which kinds of access you intend to govern and returns a file descriptor representing the ruleset. &lt;code&gt;landlock_add_rule&lt;/code&gt; adds an exception in the form of a directory you want to keep. Finally, &lt;code&gt;landlock_restrict_self&lt;/code&gt; applies the whole thing to the calling process, permanently.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;handled_access_fs&lt;/code&gt; field in the ruleset attribute is the part people get backwards. It doesn&amp;#39;t list what you&amp;#39;re allowing. It lists the access types this ruleset is responsible for, and anything in that list is denied everywhere except the paths you explicitly add. Handle read access and you lose read access to the entire filesystem until you add rules back.&lt;/p&gt;&lt;h2&gt;A Program That Restricts Itself&lt;/h2&gt;&lt;p&gt;Here is the whole thing:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#define _GNU_SOURCE
#include &amp;lt;linux/landlock.h&amp;gt;
#include &amp;lt;sys/prctl.h&amp;gt;
#include &amp;lt;sys/syscall.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;errno.h&amp;gt;

#define READ_RIGHTS (LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR)

static int create_ruleset(const struct landlock_ruleset_attr *attr)
{ return syscall(__NR_landlock_create_ruleset, attr, sizeof(*attr), 0); }

static int add_rule(int fd, const struct landlock_path_beneath_attr *pb)
{ return syscall(__NR_landlock_add_rule, fd, LANDLOCK_RULE_PATH_BENEATH, pb, 0); }

static int restrict_self(int fd)
{ return syscall(__NR_landlock_restrict_self, fd, 0); }

static int allow_read(int ruleset_fd, const char *path)
{
    struct landlock_path_beneath_attr pb = { .allowed_access = READ_RIGHTS };
    int rc;

    pb.parent_fd = open(path, O_PATH | O_CLOEXEC);
    if (pb.parent_fd &amp;lt; 0) { perror(path); return -1; }
    rc = add_rule(ruleset_fd, &amp;amp;pb);
    close(pb.parent_fd);
    return rc;
}

static void try_read(const char *path)
{
    int fd = open(path, O_RDONLY);

    if (fd &amp;lt; 0)
        printf(&amp;quot;  read %-24s FAILED (%s)\n&amp;quot;, path, strerror(errno));
    else
        { printf(&amp;quot;  read %-24s ok\n&amp;quot;, path); close(fd); }
}

int main(void)
{
    struct landlock_ruleset_attr attr = { .handled_access_fs = READ_RIGHTS };
    int ruleset_fd = create_ruleset(&amp;amp;attr);

    if (ruleset_fd &amp;lt; 0) { perror(&amp;quot;landlock_create_ruleset&amp;quot;); return 1; }
    if (allow_read(ruleset_fd, &amp;quot;/etc&amp;quot;) &amp;lt; 0) return 1;

    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror(&amp;quot;prctl&amp;quot;); return 1; }
    if (restrict_self(ruleset_fd)) { perror(&amp;quot;landlock_restrict_self&amp;quot;); return 1; }
    close(ruleset_fd);

    printf(&amp;quot;with landlock, /etc allowed:\n&amp;quot;);
    try_read(&amp;quot;/etc/hostname&amp;quot;);
    try_read(&amp;quot;/tmp/secret.txt&amp;quot;);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Build and run it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gcc -Wall -o sandbox sandbox.c
echo &amp;quot;hunter2&amp;quot; &amp;gt; /tmp/secret.txt
./sandbox&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;with landlock, /etc allowed:
  read /etc/hostname            ok
  read /tmp/secret.txt          FAILED (Permission denied)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two details in there matter. The rule refers to a directory by an open file descriptor rather than a path string, opened with &lt;code&gt;O_PATH&lt;/code&gt; so you get a handle without needing read permission on the directory itself. And &lt;code&gt;restrict_self&lt;/code&gt; takes effect immediately for the calling process, with no way to undo it.&lt;/p&gt;&lt;h2&gt;Why &lt;code&gt;no_new_privs&lt;/code&gt; is Mandatory&lt;/h2&gt;&lt;p&gt;Take the &lt;code&gt;prctl&lt;/code&gt; call out and the program stops working:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;landlock_restrict_self -&amp;gt; Operation not permitted&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#39;s &lt;code&gt;EPERM&lt;/code&gt;, and it&amp;#39;s deliberate. &lt;code&gt;PR_SET_NO_NEW_PRIVS&lt;/code&gt; tells the kernel that this process and its descendants can never gain privileges through &lt;code&gt;execve&lt;/code&gt;, which is what stops a sandboxed process from escaping by running a setuid binary.&lt;/p&gt;&lt;p&gt;Without that guarantee, a restricted process could exec &lt;code&gt;sudo&lt;/code&gt; or any setuid program and step outside the restrictions you just applied. Landlock refuses to apply itself at all rather than offer a sandbox with that hole in it. Set &lt;code&gt;no_new_privs&lt;/code&gt; first, every time.&lt;/p&gt;&lt;h2&gt;Rulesets Intersect, They Never Widen&lt;/h2&gt;&lt;p&gt;This is the property to get right. Apply a ruleset allowing &lt;code&gt;/etc&lt;/code&gt;, then apply a second allowing &lt;code&gt;/tmp&lt;/code&gt;, and ask what you can reach:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;after first ruleset:  /etc=ok               /tmp=Permission denied
after second ruleset: /etc=Permission denied  /tmp=Permission denied&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second ruleset didn&amp;#39;t add &lt;code&gt;/tmp&lt;/code&gt;. It took away &lt;code&gt;/etc&lt;/code&gt;, and left you with nothing.&lt;/p&gt;&lt;img src=&quot;https://cdn.hashnode.com/uploads/covers/6a783a81a29db580b40f1bc8/3091ccb0-3d7e-4b52-8744-83a7b32848b9.png&quot; alt=&quot;Diagram showing a Landlock sandbox narrowing in three steps: with no ruleset all five directories are readable, after a ruleset allowing /etc only /etc is readable, and after a second ruleset allowing /tmp nothing is readable at all, because the two rulesets intersect and their overlap is empty&quot; title=&quot;&quot;/&gt;&lt;p&gt;Each &lt;code&gt;restrict_self&lt;/code&gt; intersects with everything already applied. The first ruleset permitted &lt;code&gt;/etc&lt;/code&gt; and denied the rest. The second permitted &lt;code&gt;/tmp&lt;/code&gt; and denied the rest. What survives is the overlap of those two, which is empty.&lt;/p&gt;&lt;p&gt;So a Landlock sandbox is a ratchet. Every application can only tighten, never loosen, and there&amp;#39;s no operation anywhere in the API that widens what a restricted process may do. If you need a process to have access to two directories, both rules go into one ruleset before you apply it.&lt;/p&gt;&lt;p&gt;That also means you can&amp;#39;t change your mind. A long-running process that restricts itself early can&amp;#39;t be granted more later, by itself or by anyone else, short of starting a new process.&lt;/p&gt;&lt;h2&gt;What Your Children Inherit&lt;/h2&gt;&lt;p&gt;Restrictions follow &lt;code&gt;fork&lt;/code&gt; without asking:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;parent:       /etc=ok   /tmp/secret.txt=Permission denied
forked child: /etc=ok   /tmp/secret.txt=Permission denied&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The child inherits the parent&amp;#39;s Landlock domain exactly and there&amp;#39;s no flag to opt out. The same holds across &lt;code&gt;execve&lt;/code&gt;, which is the point of &lt;code&gt;no_new_privs&lt;/code&gt;: the new program starts already inside the sandbox the old one built.&lt;/p&gt;&lt;p&gt;This is what makes Landlock useful for wrapping something you didn&amp;#39;t write. Restrict yourself, then exec the thing you want contained, and it runs inside your restrictions without knowing they exist.&lt;/p&gt;&lt;h2&gt;The &lt;code&gt;exec&lt;/code&gt; Trap&lt;/h2&gt;&lt;p&gt;It also sets a trap. Take the program above, keep only &lt;code&gt;/etc&lt;/code&gt; allowed, and try to exec anything:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;allowed: /etc
execl(/usr/bin/cat) failed: Permission denied&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Executing a binary requires reading it. This ruleset handles &lt;code&gt;LANDLOCK_ACCESS_FS_READ_FILE&lt;/code&gt;, so the kernel checks whether &lt;code&gt;/usr/bin/cat&lt;/code&gt; may be read, finds no rule covering &lt;code&gt;/usr&lt;/code&gt;, and refuses before the program ever starts.&lt;/p&gt;&lt;p&gt;Add &lt;code&gt;/usr&lt;/code&gt; to the same ruleset and it works:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;allowed: /etc and /usr
devils-dell&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The general lesson is that a Landlock sandbox has to include everything the process touches, and that set is larger than you think. Your binary, its interpreter, every shared library it loads, and any config it reads at startup. &lt;code&gt;ldd&lt;/code&gt; on the binary is a good place to begin the list.&lt;/p&gt;&lt;h2&gt;Wrapping a Program You Didn&amp;#39;t Write&lt;/h2&gt;&lt;p&gt;Inheritance across &lt;code&gt;exec&lt;/code&gt; is what makes Landlock useful beyond your own code. Restrict yourself, then exec whatever you want contained, and it runs inside the sandbox without cooperating or even knowing.&lt;/p&gt;&lt;p&gt;A usable wrapper needs one addition to the program above. Handle &lt;code&gt;LANDLOCK_ACCESS_FS_EXECUTE&lt;/code&gt; alongside the read rights, allow the system directories any binary needs, then allow whatever working directory the user asked for:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#define RIGHTS (LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | \
                LANDLOCK_ACCESS_FS_EXECUTE)

static int add_path(int ruleset_fd, const char *path)
{
    struct landlock_path_beneath_attr pb = { .allowed_access = RIGHTS };
    int rc;

    pb.parent_fd = open(path, O_PATH | O_CLOEXEC);
    if (pb.parent_fd &amp;lt; 0)
        return -1;
    rc = syscall(__NR_landlock_add_rule, ruleset_fd,
                 LANDLOCK_RULE_PATH_BENEATH, &amp;amp;pb, 0);
    close(pb.parent_fd);
    return rc;
}

int main(int argc, char **argv)
{
    struct landlock_ruleset_attr attr = { .handled_access_fs = RIGHTS };
    const char *base[] = { &amp;quot;/usr&amp;quot;, &amp;quot;/lib&amp;quot;, &amp;quot;/lib64&amp;quot;, &amp;quot;/bin&amp;quot;, &amp;quot;/etc&amp;quot; };
    int fd, i;

    if (argc &amp;lt; 3) { fprintf(stderr, &amp;quot;usage: %s DIR CMD...\n&amp;quot;, argv[0]); return 2; }

    fd = syscall(__NR_landlock_create_ruleset, &amp;amp;attr, sizeof(attr), 0);
    if (fd &amp;lt; 0) { perror(&amp;quot;create_ruleset&amp;quot;); return 1; }

    for (i = 0; i &amp;lt; (int)(sizeof(base) / sizeof(*base)); i++)
        add_path(fd, base[i]);
    if (add_path(fd, argv[1]) &amp;lt; 0) { perror(argv[1]); return 1; }

    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror(&amp;quot;prctl&amp;quot;); return 1; }
    if (syscall(__NR_landlock_restrict_self, fd, 0)) { perror(&amp;quot;restrict_self&amp;quot;); return 1; }
    close(fd);

    execvp(argv[2], &amp;amp;argv[2]);
    fprintf(stderr, &amp;quot;%s: %s\n&amp;quot;, argv[2], strerror(errno));
    return 1;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The loop ignores what &lt;code&gt;add_path&lt;/code&gt; returns, so the same binary works on systems where &lt;code&gt;/lib64&lt;/code&gt; or &lt;code&gt;/bin&lt;/code&gt; are absent or symlinked somewhere else. The directory the user named is checked, because a typo there should be an error now rather than a puzzling denial later.&lt;/p&gt;&lt;p&gt;Now &lt;code&gt;cat&lt;/code&gt; and &lt;code&gt;ls&lt;/code&gt; can see the working directory and nothing else:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p /tmp/work &amp;amp;&amp;amp; echo &amp;quot;project data&amp;quot; &amp;gt; /tmp/work/notes.txt

./llrun /tmp/work cat /tmp/work/notes.txt
./llrun /tmp/work cat /tmp/secret.txt
./llrun /tmp/work ls /home&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;project data
cat: /tmp/secret.txt: Permission denied
ls: cannot open directory &amp;#39;/home&amp;#39;: Permission denied&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Neither program was modified, recompiled, or asked for consent. &lt;code&gt;bwrap&lt;/code&gt; and similar tools reach that outcome by building mount and user namespaces around the program. This gets there by asking one LSM for less, in about sixty lines, with nothing to install.&lt;/p&gt;&lt;h2&gt;Finding the Paths a Program Needs&lt;/h2&gt;&lt;p&gt;The hard part of any sandbox isn&amp;#39;t the API. It&amp;#39;s the list. Programs open far more than you expect, and a path you forget shows up as a failure somewhere deep in a run.&lt;/p&gt;&lt;p&gt;Two tools build the list for you. &lt;code&gt;ldd&lt;/code&gt; gives the shared libraries, which must be readable or the program never starts:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ldd /usr/bin/cat&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;linux-vdso.so.1 (0x00007fff85f39000)
libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4f61bb5000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4f61e0a000)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;strace&lt;/code&gt; gives everything else. Run the program unrestricted first and collect what it opens:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;strace -e trace=openat cat /etc/hostname 2&amp;gt;&amp;amp;1 | grep -oE &amp;#39;&amp;quot;/[^&amp;quot;]+&amp;quot;&amp;#39; | sort -u&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;quot;/etc/hostname&amp;quot;
&amp;quot;/etc/ld.so.cache&amp;quot;
&amp;quot;/lib/x86_64-linux-gnu/libc.so.6&amp;quot;
&amp;quot;/usr/lib/locale/locale-archive&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Four paths for a program that prints one file, and only one of them is the file you asked for. The linker cache, the C library, and the locale archive are all mandatory, which is why the wrapper allows &lt;code&gt;/usr&lt;/code&gt;, &lt;code&gt;/lib&lt;/code&gt; and &lt;code&gt;/etc&lt;/code&gt; before it allows anything you chose.&lt;/p&gt;&lt;p&gt;Once restricted, &lt;code&gt;strace&lt;/code&gt; also tells you exactly what a denial was:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;strace -f -e trace=openat ./llrun /tmp/work cat /tmp/secret.txt 2&amp;gt;&amp;amp;1 | grep EACCES&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;openat(AT_FDCWD, &amp;quot;/tmp/secret.txt&amp;quot;, O_RDONLY) = -1 EACCES (Permission denied)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#39;s the loop. Run it, read the &lt;code&gt;EACCES&lt;/code&gt; line, decide whether the path belongs in the ruleset or the program shouldn&amp;#39;t be reaching for it, then repeat. Landlock logs nothing of its own on this kernel, so &lt;code&gt;strace&lt;/code&gt; is the debugger. Kernels from 6.15 report denials through the audit subsystem, so check your version before hunting for a log that isn&amp;#39;t there.&lt;/p&gt;&lt;h2&gt;Which ABI Version You Have&lt;/h2&gt;&lt;p&gt;Landlock has grown since 5.13, and features you read about may not exist on your kernel. Ask it directly:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int v = syscall(__NR_landlock_create_ruleset, NULL, 0,
                LANDLOCK_CREATE_RULESET_VERSION);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This machine reports &lt;code&gt;1&lt;/code&gt;, which is the original from 5.13 and offers thirteen filesystem access rights:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;grep -oE &amp;quot;LANDLOCK_ACCESS_FS_[A-Z_]+&amp;quot; /usr/include/linux/landlock.h | sort -u&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;LANDLOCK_ACCESS_FS_EXECUTE      LANDLOCK_ACCESS_FS_MAKE_BLOCK
LANDLOCK_ACCESS_FS_MAKE_CHAR    LANDLOCK_ACCESS_FS_MAKE_DIR
LANDLOCK_ACCESS_FS_MAKE_FIFO    LANDLOCK_ACCESS_FS_MAKE_REG
LANDLOCK_ACCESS_FS_MAKE_SOCK    LANDLOCK_ACCESS_FS_MAKE_SYM
LANDLOCK_ACCESS_FS_READ_DIR     LANDLOCK_ACCESS_FS_READ_FILE
LANDLOCK_ACCESS_FS_REMOVE_DIR   LANDLOCK_ACCESS_FS_REMOVE_FILE
LANDLOCK_ACCESS_FS_WRITE_FILE&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Later versions added file reparenting, truncation, network rules covering TCP bind and connect, and control over device ioctls. Each arrived in its own ABI bump, so a program that wants a newer right should query the version and degrade rather than assume. Passing a right the running kernel doesn&amp;#39;t know about makes &lt;code&gt;landlock_create_ruleset&lt;/code&gt; fail with &lt;code&gt;EINVAL&lt;/code&gt;, which is a confusing error to debug if you haven&amp;#39;t checked the version first.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;You can now sandbox a process from inside itself, with no privileges and no configuration, and you know the four surprises. &lt;code&gt;no_new_privs&lt;/code&gt; comes first or nothing applies. Rulesets intersect rather than accumulate, so build one ruleset with everything in it. Children inherit, which is a feature. And read restrictions break &lt;code&gt;exec&lt;/code&gt; unless the binary&amp;#39;s path is allowed too.&lt;/p&gt;&lt;p&gt;There are a few directions to go from here. Add &lt;code&gt;LANDLOCK_ACCESS_FS_WRITE_FILE&lt;/code&gt; to &lt;code&gt;handled_access_fs&lt;/code&gt; and make a program that can read widely but write to exactly one directory. Wrap a program you didn&amp;#39;t write by restricting yourself and then calling &lt;code&gt;execve&lt;/code&gt;. Or look at how &lt;code&gt;strace&lt;/code&gt; reports the denials, which is the fastest way to build the list of paths a real program actually needs.&lt;/p&gt;&lt;h2&gt;Epilogue&lt;/h2&gt;&lt;p&gt;The interesting question about Landlock isn&amp;#39;t what it does. It&amp;#39;s what it can&amp;#39;t express. A ruleset names paths, so the unit of authority is a location in the filesystem rather than a particular file you were handed. You can say this process may read below &lt;code&gt;/etc&lt;/code&gt;. You can&amp;#39;t say this process may read the one file the user just picked, and nothing else.&lt;/p&gt;&lt;p&gt;That gap is what I&amp;#39;ve spent the last while on, building a capability-backed desktop OS in which authority arrives as a handle to one object rather than a rule about a location, with the Debian ecosystem still working underneath. Landlock does a great deal of the work, and the places it stops are where the design gets interesting.&lt;/p&gt;&lt;p&gt;I write about systems and their mysteries at thechris.in.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Sorry, Wrong Number: Debugging a Crash under Wine</title>
<link>https://blog.jchw.dev/wrong-number/</link>
<guid isPermaLink="false">spZxu8ZRqBVYiRc6g3nba576qX7L-hU5F-NzGw==</guid>
<pubDate>Mon, 14 Sep 2026 07:45:05 +0000</pubDate>
<description>A blog about software.</description>
<content:encoded>&lt;p&gt;On December 3rd, 2021, a friend of mine needed help: their program was crashing on &lt;abbr&gt;Wine&lt;/abbr&gt;, and they wanted to know how to fix it.&lt;/p&gt;&lt;p&gt;(And I&amp;#39;m only getting around to publishing this &lt;em&gt;now&lt;/em&gt;, several months later. I&amp;#39;m a bit disorganized...)&lt;/p&gt;&lt;p&gt;Normally, the answer to this question is not very complicated, because a lot of stuff works just fine in Wine provided the environment is setup correctly, and some stuff simply doesn&amp;#39;t work. Usually problems fall into one of those two categories; however, in this case, there really wasn&amp;#39;t any obvious reason (at least to me) why it shouldn&amp;#39;t work.&lt;/p&gt;&lt;p&gt;The program in question is compiled with MSys2&amp;#39;s MinGW-w64 package, using GCC 10.3. It contains a few other libraries also compiled with the same toolchain, as DLLs, including &lt;code&gt;libpng&lt;/code&gt; and &lt;code&gt;zlib&lt;/code&gt;, which I am about to become very familiar with.&lt;/p&gt;&lt;p&gt;Some debugging had already been done, and they knew which call the application was failing in: a call to &lt;code&gt;png_read_info&lt;/code&gt;. I ran it under Wine using the &lt;code&gt;WINE_DEBUG=+all&lt;/code&gt; option and generated a gigantic log file of mostly useless information. After a bit of correlation, I found the last API call before the crash: an &lt;code&gt;msvcrt._read&lt;/code&gt;, returning successfully... and then we crash.&lt;/p&gt;&lt;p&gt;After a bit of misdirection, I realized a crucial detail that I had been glancing over for a bit: the access violation was an &lt;em&gt;execute&lt;/em&gt;, &lt;em&gt;not&lt;/em&gt; a read or write. That means that RIP is landing in the middle of a page that is not executable. Hmmm. Stack corruption, somehow?&lt;/p&gt;&lt;p&gt;Something interesting about Wine is that you can run it under Valgrind, which, with a few flags, does &lt;em&gt;actually&lt;/em&gt; work correctly. But upon doing this, I discovered nothing particularly interesting, certainly nothing that would suggest stack corruption, so I moved on.&lt;/p&gt;&lt;p&gt;At this point I decided to break out rr, a special debugger that can record and replay program execution. Honestly, it&amp;#39;s a bit overkill here, but it does make it easier to analyze crashes, and this seemed like a good excuse to pull it out. There &lt;em&gt;is&lt;/em&gt; a bit of trickiness with using rr on top of Wine, but it works more or less just fine; it&amp;#39;s just a bit of a pain to get the replay working. I never quite figured out how to get debug symbols to map correctly with this Wine-under-GDB setup going on, so I had to manually explore the address space to figure out what I was looking at.&lt;/p&gt;&lt;p&gt;After much ado, the program crashes into... nowhere. It crashes at &lt;code&gt;0x2&amp;#39;fe8f&amp;#39;2910&lt;/code&gt;. Nothing is mapped here. Hmm.&lt;/p&gt;&lt;p&gt;Using the magic of rr, I can replay to some point directly before the crash and then step into it. A few hundred &lt;code&gt;stepi&lt;/code&gt;s later, and I found the culprit: &lt;code&gt;e8 20 45 7e 96&lt;/code&gt;, at the address &lt;code&gt;0x3&amp;#39;6810&amp;#39;e3eb&lt;/code&gt;. AKA, &lt;code&gt;CALL 0x2fe8f2910&lt;/code&gt;. In other words: there is an explicit CALL to nowhere.&lt;/p&gt;&lt;p&gt;At this point, I threw &lt;code&gt;libpng&lt;/code&gt; in a disassembler, and found the instruction at &lt;code&gt;0x36810e3eb&lt;/code&gt;. The instruction?&lt;/p&gt;&lt;figure&gt;&lt;a href=&quot;https://blog.jchw.dev/assets/wrong-number/image-1.png&quot;&gt;&lt;img src=&quot;https://blog.jchw.dev/assets/wrong-number/image-1.png&quot; alt=&quot;A screenshot showing a CALL instruction, CALL near ptr crc32 (E8 78 9E 03 00)&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;A call to... crc32?&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Bizarre. That CALL has a completely different address. It is &lt;code&gt;e8 78 9e 03 00&lt;/code&gt;, not &lt;code&gt;e8 20 45 7e 96&lt;/code&gt; which is non-sense and points backwards to before the entire module.&lt;/p&gt;&lt;p&gt;So who&amp;#39;s modifying the CALL? Is it the program? Is it libpng? Is it Wine?&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://blog.jchw.dev/assets/wrong-number/image-2.png&quot; alt=&quot;A screenshot of Fred Jones from Scooby Doo imminently unmasking a perpetrator.&quot; title=&quot;&quot;/&gt;&lt;/figure&gt;&lt;h3&gt;Tracing the CALL&lt;/h3&gt;&lt;p&gt;One thing we &lt;em&gt;do&lt;/em&gt; know about the &lt;code&gt;.text&lt;/code&gt; segment is that it&amp;#39;s read-only. Of course, you should at least &lt;em&gt;verify&lt;/em&gt; this in your disassembler, but I did, and indeed, it&amp;#39;s read-only. That means that in order to modify the segment, someone would need to deliberately mark it writable. On UNIX-like platforms, you would use a syscall like &lt;code&gt;mprotect&lt;/code&gt;, whereas Windows provides &lt;code&gt;VirtualProtect&lt;/code&gt; in kernel32. Thankfully, there&amp;#39;s really no way that libpng would link to &lt;code&gt;VirtualPro&lt;/code&gt;-&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://blog.jchw.dev/assets/wrong-number/image-3.png&quot; alt=&quot;A screenshot of the IDA imports panel, showing VirtualProtect and VirtualQuery being imported from KERNEL32 by the libpng DLL.&quot; title=&quot;&quot;/&gt;&lt;figcaption&gt;Goddammit.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;...what exactly is libpng doing calling this?&lt;/p&gt;&lt;figure&gt;&lt;a href=&quot;https://blog.jchw.dev/assets/wrong-number/image-4.png&quot;&gt;&lt;img src=&quot;https://blog.jchw.dev/assets/wrong-number/image-4.png&quot; alt=&quot;A call graph showing VirtualProtect being called by sub_36812E420, which is called by sub_36812E590, which is called by sub_3680F1200 (which is, effectively, the DLL&amp;#39;s entrypoint.)&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p&gt;Apparently, it reaches back to &lt;code&gt;sub_3680F1200&lt;/code&gt;, which is just the entry point of the DLL–there&amp;#39;s a stub over at the &amp;quot;true&amp;quot; entry point, but IDA does not count the &lt;code&gt;jmp&lt;/code&gt; in the call graph, so you can&amp;#39;t see it here.&lt;/p&gt;&lt;p&gt;In order to try to identify what this code was, I used the tried and true strategy of looking for interesting strings, and quickly found a few, but the most interesting was this one: &lt;code&gt;&amp;quot;Unknown pseudo relocation bit size %d&amp;quot;&lt;/code&gt; – hrm, what&amp;#39;s a pseudo relocation?&lt;/p&gt;&lt;h3&gt;What is a pseudo relocation?&lt;/h3&gt;&lt;p&gt;I&amp;#39;ve mostly glossed over many of the lower level details in this post, but I think this one merits some more attention.&lt;/p&gt;&lt;h4&gt;What is a &lt;em&gt;normal&lt;/em&gt; relocation?&lt;/h4&gt;&lt;p&gt;Before answering what a &lt;em&gt;pseudo&lt;/em&gt; relocation is, I&amp;#39;d like to discuss &lt;em&gt;regular&lt;/em&gt; relocations. When a linker links a program module, it has to pick some arbitrary &amp;quot;base address&amp;quot; to use for &lt;em&gt;position-dependent&lt;/em&gt; code and data. What does that mean? Let&amp;#39;s say you have a global, statically-initialized variable that is a pointer to another global variable. This is allowed. The pointer written into the executable file during compilation (specifically linking) is the address that &lt;em&gt;would&lt;/em&gt; be correct if the program module was loaded into its &lt;em&gt;preferred base address&lt;/em&gt;. Much code and data is position-independent, and thus does not need relocations, but any place where an absolute offset into the address space must be written, such as static pointers, relocations will be needed.&lt;/p&gt;&lt;p&gt;However, being loaded at your preferred base address is somewhat rare these days. For one thing, almost all executable loaders &lt;em&gt;need&lt;/em&gt; to support relocating the module to a different base address, because otherwise, it&amp;#39;d be impossible to simultaneously load two modules whose preferred base addresses lead to an overlap, and these cannot be coordinated ahead of time in most cases. In addition, modern AMD64 machines have plenty of address space, so for security reasons, a mitigation called ASLR is almost always used, which essentially just randomizes the base address of program modules even if they are not initially overlapping. (This is a &lt;em&gt;bit&lt;/em&gt; of an &lt;a href=&quot;https://devblogs.microsoft.com/oldnewthing/20160413-00/?p=93301&quot;&gt;oversimplification&lt;/a&gt;.)&lt;/p&gt;&lt;p&gt;If we move (that is, change the location of) the program module in memory, the addresses that the linker had to write based off of the preferred base address don&amp;#39;t line up, as the module is now at a &lt;em&gt;different&lt;/em&gt; address, and all offsets are now shifted by some value. In order to adjust this pointer, the linker stores a relocation entry in the binary during compilation for each instance of position-dependent code or data, such as our pointer. At runtime, the executable loader or runtime linker will read each relocation entry and adjust it based on the type of relocation and the offset; adding the offset between the preferred base and the actual base directly to the value present at the address. As long as there is no inadvertent position-dependent code not accounted for by relocations, everything will work perfectly fine.&lt;/p&gt;&lt;p&gt;Modern Windows uses the Portable Executable format. The PE format contains ~9 or so different kinds of relocation entries, some of which vary depending on CPU architecture. The main reason this is necessary is to handle different relocations that modify CPU instructions, where the address may be encoded into the CPU instruction in different ways that the relocation needs to be aware of. PE handles, for example, special cases for the MIPS, ARM (32-bit), and RISC-V instruction sets. (UEFI uses the PE binary format for its binaries, so in order for RISC-V to be able to support UEFI, the PE binary format needed to add support for RISC-V, too. Fun fact!)&lt;/p&gt;&lt;h4&gt;Microsoft Windows vs. everything else&lt;/h4&gt;&lt;p&gt;The thing is, though, in many other operating systems, especially UNIX-likes, relocations and symbols are different. Whereas Windows binaries have explicit Imports and Exports, and a vector of pointers called the IAT (Import Address Table,) ELF binaries have a single unified symbol table. And when it comes to relocations, ELF has a lot more types of relocations than PE.&lt;/p&gt;&lt;p&gt;Why does this matter? The answer has everything to do with linkage.&lt;/p&gt;&lt;p&gt;When you compile some C code, and it references a symbol which is not defined in that translation unit, it is treated as an &lt;em&gt;external symbol&lt;/em&gt;. Later, during linking, when the linker resolves that symbol, it can place the address of the symbol where needed, and thus, the symbol is resolved.&lt;/p&gt;&lt;p&gt;This becomes a problem when linking to other libraries and modules; the address of the symbol is not actually known until runtime, when those libraries and modules are loaded in. Because of that, you need to generate different code; code that resolves the address at runtime, then uses that address. At least on Windows, it would not be typical to generate code like this for any external symbol; it would be slow and wasteful.&lt;/p&gt;&lt;p&gt;Thankfully, there is a workaround for function calls: the linker can generate a &lt;em&gt;thunk&lt;/em&gt;; a small routine that forwards the call through the IAT, then that thunk can be used as the address to write in for the CALL instruction.&lt;/p&gt;&lt;p&gt;But what if you reference a &lt;em&gt;data&lt;/em&gt; symbol from another library or module? Or, if you try to get the address of a function symbol from another library or module? That&amp;#39;s a problem. You need to generate the aforementioned code which resolves the address first, and the compiler, not knowing that this is the case, will generate the wrong code, and the linker will not be able to deal with it.&lt;/p&gt;&lt;p&gt;With ELF, you actually can do this, using symbol-relative relocations. With PE, you are &lt;abbr&gt;S.O.L.&lt;/abbr&gt;; Or at least, you would &lt;em&gt;normally&lt;/em&gt; be.&lt;/p&gt;&lt;h4&gt;What a &lt;em&gt;pseudo-relocation&lt;/em&gt; is.&lt;/h4&gt;&lt;p&gt;Of course, it is possible to link to data symbols on Windows. This is what all of that &lt;code&gt;__declspec(dllimport)&lt;/code&gt; business is for: you can specify it on declarations of external symbols, and that way the compiler can generate code which is appropriate for linking to an external symbol in another library.&lt;/p&gt;&lt;p&gt;So what&amp;#39;s the problem?&lt;/p&gt;&lt;p&gt;Well, a lot of code written for UNIX-likes doesn&amp;#39;t mark their symbols with &lt;code&gt;__declspec(dllimport)&lt;/code&gt;, given that it is a non-standard Visual C++ extension. MinGW wants to support compiling these programs, and in order to support that, it has invented the concept of pseudo-relocations. (Or perhaps Cygwin has invented this concept; I&amp;#39;m not sure.) A pseudo-relocation is a &amp;quot;fake&amp;quot; relocation handled at runtime, by the library itself, after the real relocations are done. It does this by, at the entrypoint, walking through a list of pseudo-relocations and adjusting the pointers with some offset relative to an IAT entry. These pseudo-relocations import symbol-relative imports, just like ELF systems.&lt;/p&gt;&lt;p&gt;In other words... Pseudo-relocations are a MinGW feature that implements a special kind of &amp;quot;relocation&amp;quot; where a pointer in code or data is replaced with an address &lt;em&gt;relative to an imported symbol&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;(Truth be told, it&amp;#39;s unclear why MinGW has decided that a call to crc32 needs a pseudo-relocation, but it seems like it can happen when you pass flags to prevent thunks from being generated, and the wrong definitions to zlib to prevent it from using the proper linkage attributes on its symbols.)&lt;/p&gt;&lt;p&gt;Hopefully, you have at least as good an understanding as I do about &lt;em&gt;why&lt;/em&gt; pseudo-relocations exist, and what problem they&amp;#39;re meant to solve... but a problem remains:&lt;/p&gt;&lt;p&gt;Why does this code, which works under Windows, break under Wine? If you are particularly keen, you may already have an idea what&amp;#39;s going on, but just to make sure we&amp;#39;re going to dive into exactly what&amp;#39;s happening.&lt;/p&gt;&lt;h3&gt;Digging Deeper&lt;/h3&gt;&lt;p&gt;In order to get more insight into what&amp;#39;s going on, we can debug the pseudo-relocation implementation. I don&amp;#39;t have debug symbols for it, but that&amp;#39;s not a big deal, since the pseudo-relocation code compiles down to relatively succinct and understandable machine code.&lt;/p&gt;&lt;p&gt;Wine provides a GDB server, so you can connect a number of different debuggers. However, I hit a crucial limitation with winedbg right away: it seems to execute the loader before we have a chance to insert breakpoints, which means the libpng entrypoint has already ran before we get the chance to break on it. This leaves us with a couple of different options:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We could fudge the &lt;code&gt;was_init&lt;/code&gt; variable. It&amp;#39;s a global that the pseudo-reloc code uses to determine if it has run already; the DLL entrypoint runs for new threads, so we could just break on that, then adjust was_init so that it runs again anyways. This might work, but even if so, it&amp;#39;s not very versatile.&lt;/li&gt;&lt;li&gt;We can forgo winedbg and simply run Wine itself under GDB.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Wine under GDB&lt;/h4&gt;&lt;p&gt;When I used rr earlier, I was basically already doing this. However, rr is pretty overkill for this problem, and actually introduces some complexity of its own, so it&amp;#39;s probably easier to just forgo it for now.&lt;/p&gt;&lt;p&gt;I&amp;#39;m on NixOS, where the WINE binary on the &lt;code&gt;$PATH&lt;/code&gt; is actually a shell script. We&amp;#39;ll tell GDB to execute bash first.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;$ gdb --args bash wine Game.exe&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This won&amp;#39;t work just yet; we need to adjust the behaviors on fork and exec; then we can go.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) set follow-fork-mode child
(gdb) set follow-exec-mode new
(gdb) catch fork
Catchpoint 1 (fork)
(gdb) catch exec
Catchpoint 2 (exec)
(gdb) run&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can &lt;code&gt;continue&lt;/code&gt; a couple of times until we&amp;#39;re finally in our target binary, then flip &lt;code&gt;follow-fork-mode&lt;/code&gt; back to parent and &lt;code&gt;follow-exec-mode&lt;/code&gt; back to &lt;code&gt;same&lt;/code&gt;. I want to set a breakpoint at the point at which the &lt;code&gt;was_init&lt;/code&gt; variable is flagged. Because WINE doesn&amp;#39;t implement ASLR, our libraries end up at their preferred base addresses, so lacking symbols in GDB, I can just enter the raw addresses as determined by digging around in IDA:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) break *0x36812E5C8
Breakpoint 3 at 0x36812e5c8&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;GDB doesn&amp;#39;t give us a whole lot of feedback. Something useful you can do is have GDB print the disassembly at the instruction pointer for you:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) display/i $pc
1: x/i $pc
=&amp;gt; 0x36812e5c8: movl   $0x1,0x14b0e(%rip)        # 0x3681430e0
(gdb)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, as we step through, we can see what instruction we are on.&lt;/p&gt;&lt;p&gt;In this case, the &lt;code&gt;+0x14b0e&lt;/code&gt; address is &lt;code&gt;was_init&lt;/code&gt;. This instruction may look strange since &lt;a href=&quot;https://github.com/Alexpux/mingw-w64/blob/d90b8bb82e9b3ece71b8e505fa9b3d75747d8046/mingw-w64-crt/crt/pseudo-reloc.c#L473&quot;&gt;pseudo-reloc has &lt;code&gt;++was_init&lt;/code&gt; rather than &lt;code&gt;was_init = 1&lt;/code&gt;&lt;/a&gt;, but I think we can assume that the compiler has optimized it to assume &lt;code&gt;was_init&lt;/code&gt; is zero due to the conditional beforehand. Neat.&lt;/p&gt;&lt;p&gt;This could get pretty boring if we tried to understand and explain each instruction. I&amp;#39;ve already analyzed the function and found the relocations, so I should be able to set a conditional breakpoint that gets me into the exact spot I want to be.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://blog.jchw.dev/assets/wrong-number/image-5.png&quot; alt=&quot;IDA Pro screenshot showing a number of runtime_pseudo_reloc_item_v2 structures, highlighting the one that covers the offset of interest for us.&quot; title=&quot;&quot;/&gt;&lt;/figure&gt;&lt;p&gt;IDA Pro annoyingly shows the same address for all relocations because it&amp;#39;s marked as an array. That&amp;#39;s OK – we just need to calculate it out, and make a quick breakpoint:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) break *0x36812E69D if $rbx == 0x36813DF4C
Breakpoint 5 at 0x36812e69d&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now we can continue. Once we&amp;#39;re there, we can step around:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) stepi
0x000000036812e69f in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e69f: mov    0x4(%rbx),%esi
(gdb)
0x000000036812e6a2 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6a2: movzbl 0x8(%rbx),%edx
(gdb)
0x000000036812e6a6 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6a6: add    %r13,%rax
(gdb)
0x000000036812e6a9 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6a9: add    %r13,%rsi
(gdb)
0x000000036812e6ac in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6ac: mov    (%rax),%r15
(gdb)
0x000000036812e6af in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6af: cmp    $0x20,%edx
(gdb)
0x000000036812e6b2 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e6b2: je     0x36812e7a8
(gdb)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is just a switch statement compiled into a conditional tree. As luck would have it, all of our relocations are 32-bit (...), so this first conditional hits immediately.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb)
0x000000036812e7a8 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7a8: mov    (%rsi),%edx
(gdb)
0x000000036812e7aa in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7aa: mov    %rdx,%rcx
(gdb) nexti
0x000000036812e7ad in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7ad: or     %r14,%rdx
(gdb)
0x000000036812e7b0 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7b0: test   %ecx,%ecx
(gdb)
0x000000036812e7b2 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7b2: cmovns %rcx,%rdx
(gdb)
0x000000036812e7b6 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7b6: mov    %rsi,%rcx
(gdb)
0x000000036812e7b9 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7b9: sub    %rax,%rdx
(gdb)
0x000000036812e7bc in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7bc: add    %rdx,%r15
(gdb)
0x000000036812e7bf in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7bf: call   0x36812e420
(gdb)
0x000000036812e7c4 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7c4: mov    %r15d,(%rsi)
(gdb)
0x000000036812e7c7 in ?? ()
1: x/i $pc
=&amp;gt; 0x36812e7c7: jmp    0x36812e694
(gdb)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This code right here is the culprit. It just wrote &lt;code&gt;%r15d&lt;/code&gt; to the memory at the address pointed to by &lt;code&gt;%rsi&lt;/code&gt;. What are those values?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-term&quot;&gt;(gdb) i r r15d
r15d           0x967e4520          -1770109664
(gdb) i r rsi
rsi            0x36810e3ec         14630839276&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We have, without a doubt, located the culprit. It&amp;#39;s writing the exact same sequence of incorrect bytes we saw earlier. What the heck is wrong with it? Why isn&amp;#39;t it getting the correct address for crc32? Why is it &lt;code&gt;0x1&amp;#39;0000&amp;#39;0000&lt;/code&gt; too far forward?&lt;/p&gt;&lt;p&gt;If you haven&amp;#39;t figured it out yet, this should do it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot;&gt;# At this point, %rax points to where the IAT entry is,
# and %r15 points to the actual value in it.
rax            0x368148268         14631076456
r15            0x1fe8f2910         8565762320

# Read the value at the target into %edx.
# This is a pointer into the IAT.
mov    (%rsi),%edx

rsi            0x36810e3ec         14630839276
*rsi           0x39e78             237176
edx            0x20 -&amp;gt; 0x39e78     32 -&amp;gt; 237176

# Copy %rdx into %rcx.
mov    %rdx,%rcx
rdx            0x39e78             237176
rcx            0x0 -&amp;gt; 0x39e78      0 -&amp;gt; 237176

# Perform sign extension on %rdx copy.
or     %r14,%rdx
r14            0xffffffff00000000  -4294967296
rdx            0x39e78 -&amp;gt; 0xffffffff00039e78  237176 -&amp;gt; -4294730120

# Test %ecx for flags.
test   %ecx,%ecx
eflags         0x286               [ PF SF IF ]
ecx            0x39e78             237176

# This undoes the sign extension if the sign bit is not set.
cmovns %rcx,%rdx
eflags         0x206               [ PF IF ]
rcx            0x39e78             237176
rdx            0xffffffff00039e78 -&amp;gt; 0x39e78  -4294730120 -&amp;gt; 237176

# At this point we&amp;#39;ve undone the sign extension.

# Move relative offset of IAT into rcx, for mark_section_writable.
mov    %rsi,%rcx
rsi            0x36810e3ec         14630839276
rcx            0x39e78 -&amp;gt; 0x36810e3ec  237176 -&amp;gt; 14630839276

# %rax is the absolute address of the IAT entry. Subtract it from %rdx.
sub    %rax,%rdx
rax            0x368148268         14631076456
rdx            0x39e78 -&amp;gt; 0xfffffffc97ef1c10  237176 -&amp;gt; -14630839280

# Add %rdx to %r15.
add    %rdx,%r15
rdx            0xfffffffc97ef1c10  -14630839280
r15            0x1fe8f2910 -&amp;gt; 0xfffffffe967e4520  8565762320 -&amp;gt; -6065076960

# Call mark_section_writable
call   0x36812e420

# Write the pseudo-relocation back.
mov    %r15d,(%rsi)
rsi            0x36810e3ec         14630839276
*rsi           0x39e78 -&amp;gt; 0x967e4520  237176 -&amp;gt; -1770109664
r15d           0x967e4520          -1770109664&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Did you catch it? The distance between the instruction is greater than what can be stored in a 32-bit value. The E8 CALL instruction can only jump between [-2&lt;sup&gt;31&lt;/sup&gt;,2&lt;sup&gt;31&lt;/sup&gt;) bytes away from the RIP as of execution because it can only store a 32-bit signed offset. Unfortunately, the pseudo reloc code simply failed silently back when I was debugging this, but I believe it has been fixed and now outputs an error when this occurs, so it shouldn&amp;#39;t be so puzzling to future generations.&lt;/p&gt;&lt;h4&gt;One last thing...&lt;/h4&gt;&lt;p&gt;There is one more weird thing though. This program &lt;em&gt;works&lt;/em&gt; on Windows, reliably. Obviously, it isn&amp;#39;t loading libraries at their preferred base addresses, or it would crash. So why is this happening?&lt;/p&gt;&lt;p&gt;Well, simple: Wine doesn&amp;#39;t support ASLR, and the libraries, at their preferred addresses, wind up too far away for the pseudo-relocations.&lt;/p&gt;&lt;p&gt;However, the fact that it works seemingly reliably on Windows is very interesting. Maybe an interesting exploration would be to see exactly why Windows ASLR seems to consistently choose addresses that are unproblematic. Perhaps it&amp;#39;s because the first time after bootup that these particular modules load is in quick succession?&lt;/p&gt;&lt;p&gt;Regardless, now knowing how the problem can be fixed, it&amp;#39;s hard to be motivated to dig &lt;em&gt;too&lt;/em&gt; much deeper. It might be nice if Wine could have similar ASLR behavior to Windows, so that these problems are less likely to crop up only on Wine, but these problems could also occur on Windows with ASLR disabled, so it&amp;#39;s probably not that important.&lt;/p&gt;&lt;p&gt;Overall, I had fun debugging this issue. I&amp;#39;m also really happy with how far Wine has come, and I do not think it is a coincidence that the issue we hit was not reasonably Wine&amp;#39;s fault. I am, however, a bit sad that I didn&amp;#39;t get an opportunity to track down and fix a nasty Wine bug, but all the more happy that the reason for this is because it simply didn&amp;#39;t exist.&lt;/p&gt;&lt;p&gt;Maybe next time. :)&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Linux 7.3-rc2 Arrives Heavier Than Usual, With Torvalds Joking the Blame Falls on AI</title>
<link>https://www.ghacks.net/2026/09/08/linux-7-3-rc2-arrives-heavier-than-usual-with-torvalds-joking-the-blame-falls-on-ai/</link>
<guid isPermaLink="false">0nOZsliR7BWcoHSM95VEsjsEpq-xYGvrQdkSGw==</guid>
<pubDate>Mon, 14 Sep 2026 06:20:20 +0000</pubDate>
<description>On September 6, 2026, Linus Torvalds made available Linux 7. Thank you for being a Ghacks reader. The post Linux 7.3-rc2 Arrives Heavier Than Usual, With Torvalds Joking the Blame Falls on AI appeared first on gHacks.</description>
<content:encoded>&lt;p&gt;On September 6, 2026, Linus Torvalds made available &lt;a href=&quot;https://www.ghacks.net/category/linux/&quot;&gt;Linux&lt;/a&gt; 7.3-rc2, calling it unusually large for that stage in the development cycle which usually provides developers with a short break once the merge window has closed, on the basis of his post to the Linux Kernel Mailing List.&lt;/p&gt;&lt;p&gt;A large number of bug reports and fixes came in early. Torvalds never identified one specific cause for the size and instead settled on a more modest explanation by saying, &amp;quot;We&amp;#39;ll obviously all blame it on AI,&amp;quot; without confirming that AI tools were responsible for the increase. The stable version of Linux 7.3 is due on October 18.&lt;/p&gt;&lt;p&gt;AI and LLM-generated contributions have continued arriving throughout the 7.3 cycle.&lt;/p&gt;&lt;h2&gt;Linux 7.3-rc2 Fixes and Torvalds on Its Unusual Size&lt;/h2&gt;&lt;p&gt;The source code is available at kernel.org, and kernel testers and distribution maintainers are encouraged to run validation passes on drivers and tooling.&lt;/p&gt;&lt;p&gt;Tooling fixes made up about 20 percent of the non-driver patch volume, with filesystem, core kernel, and networking contributions filling out the rest. Drivers accounted for most of the total diff.&lt;/p&gt;&lt;p&gt;On networking, TCP and IPv6 received targeted fixes, the ksmbd SMB server gained memory-safety corrections, and NTFS and XFS both saw adjustments.&lt;/p&gt;&lt;p&gt;Graphics changes touched AMD&amp;#39;s DRM driver and the open-source Nouveau driver for NVIDIA hardware. rc2 also carried a scheduler fix for Cache Aware Scheduling misfits on hybrid CPUs that combine performance and efficiency cores, and developer Kees Cook ran a tree-wide conversion moving more kmalloc() calls to the newer kmalloc_obj() family across hundreds of files.&lt;/p&gt;&lt;p&gt;The Nouveau driver gained display fixes for NVIDIA&amp;#39;s current Blackwell GPUs. Nouveau developer Mohamed Ahmed said the fixes covered four independent groups of issues tied to the GPU System Processor, including corrections to HDMI vendor infoframes on GB20x hardware, HDMI GCP AVMute register offsets, and vblank interrupts on Blackwell cards.&lt;/p&gt;&lt;p&gt;Ahmed said the work grew out of efforts to bring HDMI 2.1 support to Nouveau, pointing to a 2.147GHz pixel clock cap as an example of a problem that needs fixing before features such as FRL, DSC, and VRR can work correctly.&lt;/p&gt;&lt;p&gt;A separate change disables the RandStruct security feature by default on systems with a usable Rust compiler toolchain, to sidestep a circular dependency between RandStruct and Rust kernel support.&lt;/p&gt;&lt;p&gt;Torvalds spent part of his post trying to identify the reason for the release&amp;#39;s size without settling on one answer. He pointed first to a late pull from the Error Detection and Correction (EDAC) subsystem that had been overlooked during the merge window, then called that explanation too minor by itself.&lt;/p&gt;&lt;p&gt;He described several filesystems sending in fixes together, alongside a sizable DRM pull, networking and BPF fixes, and contributions from a number of driver trees landing in the same window.&lt;/p&gt;&lt;p&gt;With no single item accounting for the total, he landed on the AI remark, without confirming whether AI tools were actually behind the increase.&lt;/p&gt;&lt;h2&gt;AI-Generated Linux Kernel Patches and Review Pressure&lt;/h2&gt;&lt;p&gt;AI and LLM-generated contributions have kept arriving throughout the 7.3 cycle. Kernel co-maintainer Greg Kroah-Hartman had already flagged the cycle as likely to be difficult, posting in early September that &amp;quot;this is going to be a rough -rc cycle&amp;quot; after filtering his inbox for Linux USB subsystem submissions.&lt;/p&gt;&lt;p&gt;Kroah-Hartman said his filtered queue held 1,732 of 4,807 messages tied to the USB subsystem when he first posted, a number he brought down to 1,094 of 4,170 after clearing the most obvious fixes.&lt;/p&gt;&lt;p&gt;He added that pushing back against AI-generated submissions takes time even when a patch is clearly wrong, since he does not want to reject genuine bug fixes in the process.&lt;/p&gt;&lt;p&gt;This tension has appeared in earlier Linux release candidates and echoes wider industry findings on AI-generated code and security review.&lt;/p&gt;&lt;h2&gt;Linux 7.3 Development Cycle and Stable Release Timeline&lt;/h2&gt;&lt;p&gt;The 7.3 cycle was already large before rc2. Linux 7.3-rc1 reached 40.98 million lines of code on August 30, made up of 30,937,090 lines of code, 4,912,366 lines of comments, and 5,134,418 blank lines, up from 40.42 million lines in Linux 7.2.&lt;/p&gt;&lt;p&gt;A large share of the increase came from a new set of AMD DCN6 graphics register headers, which Torvalds said accounted for about a third of the entire rc1 patch.&lt;/p&gt;&lt;p&gt;Torvalds also used the rc1 announcement to describe a system upgrade he ran mid-merge-window that went wrong, calling himself &amp;quot;a grade A nincompoop,&amp;quot; though he said the problem was resolved without lasting effects.&lt;/p&gt;&lt;p&gt;No systemic architectural issues turned up despite the higher patch volume. The stable Linux 7.3 release is scheduled for October 18, with a possible slip to October 25 if the pace of incoming patches does not ease in the coming weeks. rc2 is available now at kernel.org for testing.&lt;/p&gt;&lt;p&gt;Thank you for being a Ghacks reader. The post &lt;a href=&quot;https://www.ghacks.net/2026/09/08/linux-7-3-rc2-arrives-heavier-than-usual-with-torvalds-joking-the-blame-falls-on-ai/&quot;&gt;Linux 7.3-rc2 Arrives Heavier Than Usual, With Torvalds Joking the Blame Falls on AI&lt;/a&gt; appeared first on gHacks.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Switching to GNU Guix: A Beginner&#39;s Perspective - Wai Hon&#39;s Blog</title>
<link>https://whhone.com/posts/switching-to-gnu-guix/</link>
<guid isPermaLink="false">9Un3f-vRXgflFNmi1FIro8u1xJmMHyA0IAkONA==</guid>
<pubDate>Mon, 14 Sep 2026 01:34:24 +0000</pubDate>
<description>A beginner&#39;s perspective on migrating a home server from Arch Linux to GNU Guix, comparing with NixOS, what works well, and handling practical issues.</description>
<content:encoded>&lt;h1&gt;Switching to GNU Guix: A Beginner&amp;#39;s Perspective&lt;/h1&gt;&lt;p&gt;&lt;small&gt;2026-09-13&lt;/small&gt;
&lt;small&gt;&lt;a href=&quot;https://whhone.com/tags/linux/&quot;&gt;#linux&lt;/a&gt;&lt;/small&gt;
&lt;small&gt;&lt;a href=&quot;https://whhone.com/tags/guix/&quot;&gt;#guix&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;&lt;h2&gt;Background: A Decade of Arch Linux&lt;/h2&gt;&lt;p&gt;Arch Linux was my distribution of choice for more than a decade. With its rolling-release model, minimal base, and the invaluable ArchWiki, it felt like the final distribution I would ever need.&lt;/p&gt;&lt;p&gt;My primary Linux machine is a dedicated home server, handling services like Home Assistant, local DNS, background jobs, and developer sandboxes. For a server running 24/7, long-term stability and maintainability are critical. Over years of incremental tweaks, configuration entropy inevitably crept in. System state became scattered across &lt;code&gt;/etc&lt;/code&gt;, &lt;code&gt;/usr&lt;/code&gt;, systemd service units, and package manager transactions. Whenever I made changes, I had to keep diligent notes about which files were edited, when, and why.&lt;/p&gt;&lt;p&gt;Recent events, such as the Arch Linux AUR security incidents (which I touched upon in my &lt;a href=&quot;https://whhone.com/posts/using-caddy-with-extensions-on-archlinux/&quot;&gt;previous post on Caddy&lt;/a&gt;) and developments around Omarchy, prompted me to re-evaluate my setup. I wanted an operating system that was declarative, reproducible, and manageable entirely in code.&lt;/p&gt;&lt;h2&gt;NixOS vs GNU Guix&lt;/h2&gt;&lt;p&gt;Declarative operating systems offer a compelling answer to configuration drift. When researching options, NixOS was actually my first choice.&lt;/p&gt;&lt;h3&gt;Testing NixOS in a VM&lt;/h3&gt;&lt;p&gt;I spun up a NixOS virtual machine and spent time experimenting by replicating the core services I was running on Arch to ensure everything worked properly. It worked really well: declaring the entire system state in a configuration file with instant rollback capabilities felt like the right model for operating systems.&lt;/p&gt;&lt;p&gt;However, as I explored deeper, documentation in NixOS became a major source of friction. The newer &lt;code&gt;nix&lt;/code&gt; command line interface and Flakes remain experimental features that are not yet enabled by default or standardized across the ecosystem, leading to divergent documentation and tutorials. Finding guidance was further complicated by the presence of two separate wikis.&lt;/p&gt;&lt;h3&gt;Discovering GNU Guix&lt;/h3&gt;&lt;p&gt;While learning more about NixOS, I came across David Wilson’s video from System Crafters: &lt;a href=&quot;https://www.youtube.com/watch?v=PiAMRXYIri0&quot;&gt;Why I Choose Guix Over NixOS&lt;/a&gt;. As a fan of David Wilson, his arguments resonated strongly with me. Shortly after, I also watched YouTux’s video, &lt;a href=&quot;https://www.youtube.com/watch?v=MtYWp8sCsiE&amp;amp;t&quot;&gt;One of the Best Linux Distros Isn’t Even in DistroWatch’s Top 100&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;These videos prompted me to research GNU Guix and try it inside a VM.&lt;/p&gt;&lt;p&gt;GNU Guix shares the same core architectural foundation as NixOS (functional package management, declarative configuration, and atomic rollbacks), but its design choices felt much more cohesive:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Language (GNU Guile Scheme vs Nix DSL):&lt;/strong&gt; Nix uses its own bespoke domain-specific language. Guix configurations are written entirely in GNU Guile, a general-purpose Scheme (Lisp). As an Emacs user accustomed to Emacs Lisp, Scheme felt familiar and expressive. Rather than learning a specialized configuration syntax, I could leverage a real programming language with first-class functions, macros, and modules.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Init System (GNU Shepherd vs systemd):&lt;/strong&gt; NixOS builds on systemd, while Guix System uses GNU Shepherd as its service manager. In Guix, Shepherd services are also defined in Guile Scheme. Everything from package recipes to system daemons to PID 1 shares a unified language and data model.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; Guix’s documentation is remarkably cohesive. Even though some community tutorials can be dated, the official GNU Guix reference manual is consistent, comprehensive, and avoids the fragmented wiki landscape of Nix.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Philosophy (GNU Libre Standards vs Pragmatism):&lt;/strong&gt; NixOS takes a pragmatic stance, offering toggles for proprietary software and unfree drivers. GNU Guix strictly adheres to the GNU Free System Distribution Guidelines, shipping the Linux-libre kernel and free software exclusively by default.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This philosophical strictness has its trade-offs. For my home server, which connects to the network through an Ethernet cable, proprietary Wi-Fi firmware is unnecessary, and the Linux-libre kernel works out of the box. The purity and auditability feel satisfying, though it does mean dealing with a more curated package catalog. Also, a personal server is personal, I can have my own opinion – I prefer purity over pragmatism, but I think GNU Guix is pragmatic enough for my use cases.&lt;/p&gt;&lt;p&gt;Between the familiarity of Scheme, the unified architecture, and its close kinship with Emacs, I decided to make the switch to GNU Guix.&lt;/p&gt;&lt;h2&gt;What I Like as a Beginner&lt;/h2&gt;&lt;h3&gt;Unified Declarative Config in Git&lt;/h3&gt;&lt;p&gt;With GNU Guix, the entire operating system configuration lives in code and is tracked in Git. I manage both Guix System (operating system declarations, system daemons, kernel parameters) and Guix Home (user packages, shell environments, and dotfiles) within a single literate Org-mode file (&lt;code&gt;guix.org&lt;/code&gt;) using Org Babel.&lt;/p&gt;&lt;p&gt;At any point, I can see exactly which packages are installed and which services are active directly from the codebase. In the past, I hesitated to invest in complex system configurations because maintaining them across updates was fragile. With Guix, configuring the operating system feels as manageable and predictable as tweaking my Emacs configuration.&lt;/p&gt;&lt;h3&gt;Flexible Guile Configuration&lt;/h3&gt;&lt;p&gt;Guix configurations are written in a full-featured programming language rather than static YAML or JSON. This gives immense flexibility when composing services.&lt;/p&gt;&lt;p&gt;Using Guix’s service extension mechanism with &lt;code&gt;simple-service&lt;/code&gt;, you can extend existing system services cleanly without modifying base declarations. In a traditional distribution, deploying a service forces you to fragment its configuration across completely separate subsystems: a systemd unit in &lt;code&gt;/etc/systemd/system/&lt;/code&gt;, and reverse proxy blocks in &lt;code&gt;/etc/nginx/conf.d/&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;With Guix, you can co-locate a service and its surrounding infrastructure side by side in the exact same configuration block:&lt;/p&gt;&lt;div&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;;; Home Assistant container
(simple-service &amp;#39;home-assistant-container
                oci-service-type
                (oci-extension
                 (containers
                  (list
                   (oci-container-configuration
                    (provision &amp;quot;home-assistant&amp;quot;)
                    (image &amp;quot;ghcr.io/home-assistant/home-assistant:stable&amp;quot;)
                    ...details config...)))))

;; Inject the Nginx reverse proxy configuration for Home Assistant
(simple-service &amp;#39;home-assistant-nginx-server
                nginx-service-type
                (list
                 (nginx-server-configuration
                  (inherit ssl-server-configuration)
                  (server-name (list (string-append &amp;quot;home.&amp;quot; domain)))
                  (locations
                   (list
                    (nginx-location-configuration
                     ...details config...)))))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This architectural clarity makes understanding, modifying, or removing a service self-contained and painless.&lt;/p&gt;&lt;h3&gt;Streamlined Shepherd Timers&lt;/h3&gt;&lt;p&gt;Another example is Shepherd Timers. Defining scheduled jobs in Guix is also much more streamlined than in traditional distributions. In systemd, setting up a recurring job requires declaring a &lt;code&gt;.service&lt;/code&gt; file and a separate &lt;code&gt;.timer&lt;/code&gt; unit.&lt;/p&gt;&lt;p&gt;With GNU Shepherd in Guix, you can declare the executable script, its dependencies, and its schedule together in a single Guile expression:&lt;/p&gt;&lt;div&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(let* ((duckdns-script
        (program-file
         &amp;quot;duckdns-update&amp;quot;
         (with-extensions (list guile-gnutls) ;required by (web client)
                          #~(begin
                              (use-modules (ice-9 textual-ports)
                                           (web client))
                              (let ((token (string-trim-both
                                            (call-with-input-file &amp;quot;/etc/secrets/duckdns.token&amp;quot;
                                              get-string-all)))
                                    (query-template (string-append &amp;quot;https://www.duckdns.org/&amp;quot;
                                                                   &amp;quot;update?domains=&amp;lt;mydomain&amp;gt;&amp;quot;
                                                                   &amp;quot;&amp;amp;token=~a&amp;amp;ip=&amp;quot;)))
                                (http-get (format #f query-template token)))))))
       (duckdns-timer
        (shepherd-timer &amp;#39;(duckdns)
                        &amp;quot;*/5 * * * *&amp;quot;
                        #~(#$duckdns-script)
                        #:requirement &amp;#39;(networking)
                        #:documentation &amp;quot;Update personal domain IP on DuckDNS every 5 minutes.&amp;quot;)))
  (simple-service &amp;#39;duckdns-timer
                  shepherd-root-service-type
                  (list duckdns-timer)))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Sandboxed Containers with &lt;code&gt;guix shell&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;guix shell&lt;/code&gt; command has transformed how I run ad-hoc software. Instead of polluting my profile with one-off utilities, &lt;code&gt;guix shell&lt;/code&gt; creates an ephemeral environment that is cleaned up when the session ends.&lt;/p&gt;&lt;p&gt;Furthermore, its container mode (&lt;code&gt;guix shell -C&lt;/code&gt; or &lt;code&gt;--container&lt;/code&gt;) makes lightweight isolation trivial. By specifying exactly which directories (&lt;code&gt;--share&lt;/code&gt;) and network access (&lt;code&gt;--network&lt;/code&gt;) to expose, I can run untrusted commands or AI coding agents inside an isolated sandbox.&lt;/p&gt;&lt;p&gt;For example, I run the Antigravity CLI within a sandbox granting access only to the current working directory, its configuration, and necessary binaries:&lt;/p&gt;&lt;div&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Run Antigravity CLI in a Guix sandbox with access to its config and the project directories.
agy-guix() {
    guix shell --container --network --emulate-fhs \
         --share=&amp;quot;$PWD&amp;quot; \
         --share=&amp;quot;$HOME/.gemini&amp;quot; \
         --share=&amp;quot;$HOME/.local/bin&amp;quot; \
         --preserve=&amp;#39;^(TERM)$&amp;#39; \
         coreutils nss-certs bash guix guile emacs git ripgrep fd zip unzip -- $HOME/.local/bin/agy &amp;quot;$@&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Knowing an agent cannot access arbitrary files outside its granted path makes experimentation much safer.&lt;/p&gt;&lt;h3&gt;Purity and the Minimal Bootstrap Seed&lt;/h3&gt;&lt;p&gt;By default, GNU Guix is strictly libre. It ships with the Linux-libre kernel and avoids proprietary binary blobs.&lt;/p&gt;&lt;p&gt;Beyond day-to-day use, Guix’s architectural focus on bootstrapping integrity (reducing the bootstrap binary seed down to around 357 bytes through the stage0/Mes bootstrap) provides a strong sense of technical rigor. Knowing the system can be built from minimal, auditable foundations provides real trust in the underlying stack.&lt;/p&gt;&lt;h2&gt;Issues and How I Handle Them&lt;/h2&gt;&lt;h3&gt;Slow &lt;code&gt;guix pull&lt;/code&gt; and Source Builds&lt;/h3&gt;&lt;p&gt;A fundamental difference between Guix and Arch Linux is that Guix is a source-based distribution at its core, backed by substitute servers that distribute prebuilt binaries.&lt;/p&gt;&lt;p&gt;If a newly pulled channel commit has not yet been built by the substitute build farm (such as &lt;code&gt;ci.guix.gnu.org&lt;/code&gt; or Bordeaux), your machine will fall back to compiling the packages locally. While this architecture empowers powerful capabilities like &lt;code&gt;guix challenge&lt;/code&gt; (verifying build reproducibility against other servers) and &lt;code&gt;guix time-machine&lt;/code&gt; (traveling back to any historical revision), waiting for long local builds on a home server can be tedious.&lt;/p&gt;&lt;p&gt;To avoid unexpected local compilation, my practical workaround is to pin &lt;code&gt;guix pull&lt;/code&gt; to a specific commit from a day or two earlier, ensuring substitutes are already built and cached:&lt;/p&gt;&lt;h3&gt;Addressing the Package Gap&lt;/h3&gt;&lt;p&gt;The most noticeable hurdle for a beginner coming from Arch Linux is repository size. The official Guix channel has strict libre standards and a smaller catalog than the Arch User Repository (AUR). Common utilities like &lt;code&gt;hugo&lt;/code&gt; and &lt;code&gt;caddy&lt;/code&gt; are not present in the official channel.&lt;/p&gt;&lt;p&gt;In practice, there are several practical ways I handle this gap:&lt;/p&gt;&lt;h4&gt;1. Writing Custom Package Definitions&lt;/h4&gt;&lt;p&gt;Writing a package definition in Scheme is straightforward. You can define a package that builds from source or downloads an official upstream release archive:&lt;/p&gt;&lt;div&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define hugo
  (package
    (name &amp;quot;hugo&amp;quot;)
    (version &amp;quot;0.165.0&amp;quot;)
    (source (origin
              (method url-fetch)
              (uri (string-append
                    &amp;quot;https://github.com/gohugoio/hugo/releases/download/v&amp;quot;
                    version &amp;quot;/hugo_&amp;quot; version &amp;quot;_linux-amd64.tar.gz&amp;quot;))
              (sha256 (base32 &amp;quot;0...&amp;quot;))))
    (build-system trivial-build-system)
    ...))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Hugo, I created a local package definition downloading the official prebuilt binary, making it available seamlessly to my system and deploy scripts.&lt;/p&gt;&lt;h4&gt;2. Running Ephemeral Toolchains via &lt;code&gt;guix shell&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;For tools that exist within language ecosystems, &lt;code&gt;guix shell&lt;/code&gt; can pair with ecosystem runners (&lt;code&gt;uvx&lt;/code&gt;, &lt;code&gt;npx&lt;/code&gt;) without installing packages globally:&lt;/p&gt;&lt;div&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# That is how I publish my blog to Cloudflare now.
guix shell node -- npx -y wrangler&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4&gt;3. Generating Definitions with &lt;code&gt;guix import&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;When a package is missing, &lt;a href=&quot;https://guix.gnu.org/manual/1.5.0/en/html_node/Invoking-guix-import.html&quot;&gt;&lt;code&gt;guix import&lt;/code&gt;&lt;/a&gt; can automatically generate package definitions from upstream registries, such as PyPI, Crates.io, CPAN, or GNU ELPA. This significantly reduces the manual effort of writing package recipes.&lt;/p&gt;&lt;h4&gt;4. Switching to Readily Available Alternatives&lt;/h4&gt;&lt;p&gt;Sometimes the simplest path is adopting software that is already a first-class citizen in Guix. Rather than maintaining a custom Caddy setup with third-party plugins, I switched back to Nginx combined with Certbot. Both are well-supported native services in Guix System, simplifying long-term maintenance.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;It has been a month since migrating my home server to GNU Guix. Managing OS state declaratively through Git has eliminated configuration drift, and Guile Scheme provides a cohesive environment that complements Emacs. While adapting to a smaller package ecosystem and managing substitute timing requires occasional adjustments, the stability, reproducibility, and container isolation make it a dependable foundation.&lt;/p&gt;&lt;p&gt;In my free time, I have started reading the legendary SICP (Structure and Interpretation of Computer Programs) to deepen my understanding of Scheme and functional programming.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Flare-On 11 – Task 5</title>
<link>https://hshrzd.wordpress.com/2024/12/08/flare-on-11-task-5/</link>
<guid isPermaLink="false">TdS_2UZXq5X6mahea3T0aM2-Mc_KILKtxPHN7A==</guid>
<pubDate>Sun, 13 Sep 2026 17:34:36 +0000</pubDate>
<description>Flare-On is an annual CTF run by Mandiant Flare Team. In this series of writeups I present solutions to some of my favorite tasks from this year. All the sourcecodes are available on my Github, in dedicated repository: flareon2024. The … Continue reading →</description>
<content:encoded>Flare-On is an annual CTF run by Mandiant Flare Team. In this series of writeups I present solutions to some of my favorite tasks from this year. All the sourcecodes are available on my Github, in dedicated repository: flareon2024. The … &lt;a href=&quot;https://hshrzd.wordpress.com/2024/12/08/flare-on-11-task-5/&quot;&gt;Continue reading &lt;span&gt;→&lt;/span&gt;&lt;/a&gt;</content:encoded>
</item>
<item>
<title>Fuzzing Under The Cave: Hunting Bugs In Batman-adv</title>
<link>https://fuzzinglabs.com/fuzzing-batman-adv/</link>
<enclosure type="image/jpeg" length="0" url="https://fuzzinglabs.com/wp-content/uploads/2026/09/Screenshot-2026-09-03-at-08.04.10.png"></enclosure>
<guid isPermaLink="false">bmzVXsqXlgiTzh5p3Wo6Ps61StHf7n6BKu4i5Q==</guid>
<pubDate>Sun, 13 Sep 2026 16:43:29 +0000</pubDate>
<description>batman-adv&#39;s routing.c had 0% Syzbot coverage. We wrote a Syzlang grammar, fuzzed it with Syzkaller, and found three Linux kernel bugs, one now in mainline.</description>
<content:encoded>&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We went looking for an under-tested corner of the Linux kernel and landed on &lt;strong&gt;batman-adv&lt;/strong&gt;, the mesh networking subsystem, whose &lt;code&gt;routing.c&lt;/code&gt; sat at 0% coverage on Syzbot. This post walks through how we wired Syzkaller up to fuzz the Ethernet frame reception path — including the Syzlang grammar we had to write from scratch — and the three bugs that came out of it: a 16-bit integer overflow in OGM fragmentation (now patched in mainline), a use-after-free race in the throughput meter, and an integer truncation leading to an out-of-bounds read in the translation table TVLV handler.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;Research during a grace period&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We had some spare time to conduct vulnerability research on an open subject. We needed to find an interesting target where we could learn something new and related to the Linux kernel. Thus, we searched through Linux subsystems to find our happiness. While looking at &lt;a href=&quot;https://syzkaller.appspot.com/upstream/coverage/subsystems?period=month&quot;&gt;Syzbot&lt;/a&gt;‘s coverage, we noticed that the subsystem &lt;code&gt;batman&lt;/code&gt; had a file called &lt;code&gt;routing.c&lt;/code&gt; with 0% of coverage:&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
															&lt;img src=&quot;https://fuzzinglabs.com/wp-content/uploads/2026/09/batman-adv-syzbot-coverage.png&quot; alt=&quot;Syzbot coverage report showing 0% coverage on routing.c in the batman-adv subsystem&quot; title=&quot;&quot;/&gt;															&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We determined there was an opportunity to fuzz the ethernet frames receival logic.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;What is BATMAN-ADV?&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;B.A.T.M.A.N. for &lt;strong&gt;B&lt;/strong&gt;etter &lt;strong&gt;A&lt;/strong&gt;pproach &lt;strong&gt;T&lt;/strong&gt;o &lt;strong&gt;M&lt;/strong&gt;obile &lt;strong&gt;A&lt;/strong&gt;d hoc &lt;strong&gt;N&lt;/strong&gt;etworking is a routing protocol designed by the Freifunk community for multi-hop ad-hoc mesh networks. The batman-adv implementation works on the Data-link layer (L2) of the OSI model and is implemented as a Linux kernel module.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We can think of a batman-adv as a big switch where we have devices that can be inter-connected as peers. The protocol uses Originator Messages and Echo Location Protocol (on batman-adv V) to maintain routing information. There are also other utilities but we will not describe them as they are already well documented by the maintainers.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
															&lt;img src=&quot;https://fuzzinglabs.com/wp-content/uploads/2026/09/batman-adv-mesh-switch.png&quot; alt=&quot;batman-adv mesh network represented as a big switch connecting peer devices&quot; title=&quot;&quot;/&gt;															&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;Fuzzing batman-adv&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h4&gt;Fuzzing Methodology&lt;/h4&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We used Syzkaller which is a coverage-guided kernel fuzzer. We had experience using it and since Syzbot is based on it, we could reach the same code paths using the existing batman-adv grammar that ensures we can trigger messages to manage the subsystem through a netlink socket (This is a common pattern used to communicate through kernel subsystems).&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We already worked on the &lt;a href=&quot;https://fuzzinglabs.com/repro-cve-2026-23111/&quot;&gt;nftables subsystem&lt;/a&gt;, which also involved fuzzing the network reception part. During this work, we discovered the &lt;a href=&quot;https://xairy.io/articles/syzkaller-external-network&quot;&gt;blog post from xairy.io&lt;/a&gt; that uses TUN/TAP to send network traffic to the VM’s network stack.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;TUN/TAP is a subsystem that provides virtual network devices. The goal is to have a mechanism to communicate network traffic through userland programs. It is a tool often used by VPN applications to encapsulate the network frames/packets:&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
															&lt;img src=&quot;https://fuzzinglabs.com/wp-content/uploads/2026/09/tun-tap-virtual-network-device.png&quot; alt=&quot;TUN/TAP virtual network device passing traffic between userland programs and the kernel network stack&quot; title=&quot;&quot;/&gt;															&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;Syzkaller provides a pseudo-syscall named &lt;code&gt;syz_emit_ethernet&lt;/code&gt; for these use cases. However, we needed to adapt some parts of the executor code to initialize the bat0 interface correctly.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h4&gt;Fuzzing implementation&lt;/h4&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;Since we managed to setup Syzkaller to fuzz the frame receival logic, we needed to make sure the grammar for the different types of messages exist. Syzkaller uses Syzlang language to define grammars for syscalls. There is the &lt;code&gt;sys/linux/vnet.txt&lt;/code&gt; file to describe the network protocol messages. There was no existing grammar for the batman-adv messages so we had to implement them directly in this file. To provide correct Syzlang descriptions for each message, we based ourselves on the &lt;code&gt;include/uapi/linux/batadv_packet.h&lt;/code&gt; file.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-git&quot;&gt;eth2_packet [
        ...
+       batman_adv eth2_packet_t[ETH_P_BATMAN, batman_packet]
+] [varlen]

[...]

+include &amp;lt;uapi/linux/batadv_packet.h&amp;gt;
+
+batman_packet [
+       batman_packet_ogm batman_packet_ogm_t
+       batman_packet_ogm2 batman_packet_ogm2_t
+       batman_packet_elp batman_packet_elp_t
+       batman_packet_multicast batman_packet_multicast_t
+       batman_packet_icmp batman_packet_icmp_t
+       batman_packet_coded batman_packet_coded_t
+       batman_packet_unicast_tvlv batman_packet_unicast_tvlv_t
+       batman_packet_icmp_tp batman_packet_icmp_tp_t
+       batman_packet_icmp_rr batman_packet_icmp_rr_t
+       batman_packet_unicast batman_packet_unicast_t
+       batman_packet_unicast_ext batman_packet_unicast_ext_t
+       batman_packet_fragmented_unicast batman_packet_fragmented_unicast_t
+       batman_packet_broadcast batman_packet_broadcast_t
+] [varlen]

[...]

+batman_packet_ogm_t {
+       hdr batman_header_t[const[BATADV_IV_OGM, int8]]
+       ttl int8
+       flags const[0, int8]
+       seqno int32be
+       orig mac_addr
+       prev_sender mac_addr
+       reserved const[0, int8]
+       tq int8
+       tvlv_len int16be
+} [packed]&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;Vulnerabilities discovered&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h4&gt;Bug 1: Integer Overflow during frame fragmentation&lt;/h4&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;With the complete setup, we quickly found our first bug in batman-adv.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
															&lt;img src=&quot;https://fuzzinglabs.com/wp-content/uploads/2026/09/batman-adv-ogm-buff-pos-overflow.png&quot; alt=&quot;Syzkaller crash report for the integer overflow in batadv_iv_ogm_send_to_if&quot; title=&quot;&quot;/&gt;															&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We searched why the bug was triggered and here is our analysis. There is a function call to &lt;code&gt;batadv_iv_ogm_send_to_if&lt;/code&gt; to send the OGM message to a given interface. It also handles the fragmentation.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-c&quot;&gt;/* send a batman ogm to a given interface */
static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
                                     struct batadv_hard_iface *hard_iface)
{
        struct batadv_priv *bat_priv = netdev_priv(hard_iface-&amp;gt;soft_iface);
        const char *fwd_str;
        u8 packet_num;
        s16 buff_pos;
        struct batadv_ogm_packet *batadv_ogm_packet;
        struct sk_buff *skb;
        u8 *packet_pos;

        if (hard_iface-&amp;gt;if_status != BATADV_IF_ACTIVE)
                return;

        packet_num = 0;
        buff_pos = 0;
        packet_pos = forw_packet-&amp;gt;skb-&amp;gt;data;
        batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;

        /* adjust all flags and log packets */
        while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet-&amp;gt;packet_len,
                                         batadv_ogm_packet)) {
                [...]

                buff_pos += BATADV_OGM_HLEN;
                buff_pos += ntohs(batadv_ogm_packet-&amp;gt;tvlv_len);
                packet_num++;
                packet_pos = forw_packet-&amp;gt;skb-&amp;gt;data + buff_pos;
                batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
        }

        [...]
}&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We found out that there is a variable named &lt;code&gt;buff_pos&lt;/code&gt; that stores the current buffer position to separate the OGM messages from the forward packet. We noted that the variable stores this information on a signed integer of 16 bits. There is a size check that is done on this variable in the &lt;code&gt;batadv_iv_ogm_aggr_packet&lt;/code&gt; function that can be called in the previous function multiple times.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-c&quot;&gt;/**
 * batadv_iv_ogm_aggr_packet() - checks if there is another OGM attached
 * @buff_pos: current position in the skb
 * @packet_len: total length of the skb
 * @ogm_packet: potential OGM in buffer
 *
 * Return: true if there is enough space for another OGM, false otherwise.
 */
static bool
batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
                          const struct batadv_ogm_packet *ogm_packet)
{
        int next_buff_pos = 0;

        /* check if there is enough space for the header */
        next_buff_pos += buff_pos + sizeof(*ogm_packet);
        if (next_buff_pos &amp;gt; packet_len)
                return false;

        /* check if there is enough space for the optional TVLV */
        next_buff_pos += ntohs(ogm_packet-&amp;gt;tvlv_len);

        return next_buff_pos &amp;lt;= packet_len;
}&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;However, this function compares our &lt;code&gt;buff_pos&lt;/code&gt; variable against a signed 32 bits integer. After some debugging, we noticed the variable signed on 16 bits can overflow with large frames, which caused the condition to still pass since we are below the &lt;code&gt;packet_len&lt;/code&gt; with a negative value.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;The patch was fairly simple as we simply needed to change &lt;code&gt;buff_pos&lt;/code&gt; into a signed 32 bits integer variable in the &lt;code&gt;batadv_iv_ogm_send_to_if&lt;/code&gt; function. Since it was an unknown bug, we were able to send the patch to the maintainers. The &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=0799e5943611006b346b8813c7daf7dd5aa26bfd&quot;&gt;patch&lt;/a&gt; is now merged into the Linux kernel mainline.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h4&gt;Bug 2: Race condition on throughput meter when interface is deleted&lt;/h4&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;Syzkaller showed us a slab use-after-free bug on the &lt;code&gt;batadv_find_router&lt;/code&gt; function. We analyzed the KASAN trace and started to understand why the bug occurred. We understood that we needed to initiate a ThroughputMeter (TP) which is a tool to calculate the bandwidth in the mesh network. It can be triggered through a netlink socket using the &lt;code&gt;BATADV_CMD_TP_METER&lt;/code&gt; message.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;This action creates a &lt;code&gt;kthread&lt;/code&gt; in the &lt;code&gt;batadv_tp_start_kthread&lt;/code&gt; function.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-c&quot;&gt;static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars)
{
	struct task_struct *kthread;
	struct batadv_priv *bat_priv = tp_vars-&amp;gt;common.bat_priv;
	u32 session_cookie;

	kref_get(&amp;amp;tp_vars-&amp;gt;common.refcount);
	kthread = kthread_create(batadv_tp_send, tp_vars, &amp;quot;kbatadv_tp_meter&amp;quot;);
	
        [...]

	wake_up_process(kthread);
}&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;We also checked where the use-after-free occurred. After reading the code, we determined it happened in &lt;code&gt;batadv_find_router&lt;/code&gt; when trying to access an attribute of the &lt;code&gt;batadv_priv&lt;/code&gt; structure. This is interesting because it contains information about the mesh interface. This helped determine that there was a race condition because of the &lt;code&gt;kthread&lt;/code&gt; trying to access data when the interface was already deleted.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;However, the bug was already known and patches were already implemented in the mailing lists.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h4&gt;Bug 3: Integer truncation when computing the VLAN size when receiving a unicast packet with a TT TVLV&lt;/h4&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;A TVLV (Type Version Length Value) is a “container” that can be appended to some packets (such as OGM or Unicast) to send information to other nodes. For this bug, we will have a look at the Translation Table (TT) TVLV (&lt;a href=&quot;https://www.open-mesh.org/doc/batman-adv/TVLV.html#translation-table-messages&quot;&gt;see the open-mesh documentation&lt;/a&gt;). Its objective is to advertise local non-mesh clients. Here is the format of the TVLV:&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-c&quot;&gt;0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   TVLV 0x04   |    Version    |             Length            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   TT Flags    |     TTVN      |       Number of VLANs         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        CRC32_vlan1                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       VID_vlan1               |       reserved_vlan1          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        CRC32_vlan2                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       VID_vlan2               |       reserved_vlan2          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       ...................                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        CRC32_vlanN                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       VID_vlanN               |       reserved_vlanN          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| flags_change1 |          reserved_change1                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       mac_addr_change1...                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     ...mac_addr_change1       |          vid_change1          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| flags_change2 |          reserved_change2                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       mac_addr_change2...                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     ...mac_addr_change2       |          vid_change2          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       ...................                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| flags_changeM |          reserved_changeM                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       mac_addr_changeM...                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     ...mac_addr_changeM       |          vid_changeM          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;The bug is in &lt;code&gt;batadv_tt_tvlv_unicast_handler_v1&lt;/code&gt; when computing the size of the vlans:&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
							&lt;div&gt;
			&lt;pre&gt;				&lt;code class=&quot;language-c&quot;&gt;/**
 * batadv_tt_tvlv_unicast_handler_v1() - process incoming (unicast) tt tvlv
 *  container
 * @bat_priv: the bat priv with all the mesh interface information
 * @src: mac address of tt tvlv sender
 * @dst: mac address of tt tvlv recipient
 * @tvlv_value: tvlv buffer containing the tt data
 * @tvlv_value_len: tvlv buffer length
 *
 * Return: NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
 * otherwise.
 */
static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
					     u8 *src, u8 *dst,
					     void *tvlv_value,
					     u16 tvlv_value_len)
{
	struct batadv_tvlv_tt_data *tt_data;
	u16 tt_num_entries;
	u16 tt_vlan_len;
	char tt_flag;
	bool ret;

	if (tvlv_value_len &amp;lt; sizeof(*tt_data))
		return NET_RX_SUCCESS;

	tt_data = tvlv_value;
	tvlv_value_len -= sizeof(*tt_data);

	tt_vlan_len = flex_array_size(tt_data, vlan_data,
				      ntohs(tt_data-&amp;gt;num_vlan));

	if (tvlv_value_len &amp;lt; tt_vlan_len)
		return NET_RX_SUCCESS;

	tvlv_value_len -= tt_vlan_len;
	tt_num_entries = batadv_tt_entries(tvlv_value_len);
        [...]
}&lt;/code&gt;
			&lt;/pre&gt;
		&lt;/div&gt;
						&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;The function &lt;code&gt;flex_array_size&lt;/code&gt; returns a &lt;code&gt;size_t&lt;/code&gt;, which will be truncated when assigned to &lt;code&gt;tt_vlan_len&lt;/code&gt; which is a &lt;code&gt;u16&lt;/code&gt;. This bug will later cause an out-of-bounds read.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;Conclusion&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;This work showed us the importance of analyzing what was already done and what was not well explored. With this first analysis, we identified the routing spot in batman-adv. Using existing solutions like Syzkaller with its networking utilities and our custom made Syzlang grammar, we managed to find and report an unknown bug. There are also other opportunities to explore in the batman-adv subsystem since we can tweak some parameters such as the protocol version (e.g. this changes the routing algorithm). This ensures that we explore other code paths that could be complex for the fuzzer to setup directly through the normal grammar since mutation of the corpus can take some time.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;Sources&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.open-mesh.org/projects/batman-adv/wiki&quot;&gt;B.A.T.M.A.N. advanced — project wiki (open-mesh.org)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://downloads.open-mesh.org/batman/papers/batman-adv_network_coding.pdf&quot;&gt;batman-adv network coding (PDF, open-mesh.org)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://syzkaller.appspot.com/upstream&quot;&gt;Syzbot dashboard — upstream Linux&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://xairy.io/articles/syzkaller-external-network&quot;&gt;Andrey Konovalov — Fuzzing the Linux network stack externally with syzkaller&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.open-mesh.org/doc/batman-adv/&quot;&gt;batman-adv protocol documentation (open-mesh.org)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;&lt;b&gt;Alexis &amp;amp; Lyes&lt;/b&gt;&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
					&lt;h3&gt;About Us&lt;/h3&gt;				&lt;/div&gt;
				&lt;/div&gt;&lt;div&gt;
				&lt;div&gt;
									&lt;p&gt;Founded in 2021, FuzzingLabs is an offensive security company specializing in fuzzing, vulnerability research and reverse engineering on firmware, binaries and embedded systems. Our team has published 20+ CVEs, found over 1,500 bugs and won three Pwn2Own competitions. We also build FuzzForge, an autonomous offensive security platform for continuous validation of firmware, binaries and embedded systems.&lt;/p&gt;								&lt;/div&gt;
				&lt;/div&gt;</content:encoded>
</item>
<item>
<title>Immurok Fingerprint Key Unlocks Linux, Approves SSH And AI Agents</title>
<link>https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/</link>
<enclosure type="image/jpeg" length="0" url="https://gadgeteer.co.za/wp-content/uploads/2026/09/immurok-touch.webp"></enclosure>
<guid isPermaLink="false">MkA_16LZvXWVc6lK7cD1Lg-wrzkiN57Zpy0tGQ==</guid>
<pubDate>Sat, 12 Sep 2026 22:54:39 +0000</pubDate>
<description>“It is a tiny wireless box that can unlock your desktop session, approve a sudo command, authenticate via polkit, log you into a server over SSH, generate</description>
<content:encoded>Skip to content&lt;div&gt;
			&lt;div&gt;
									&lt;div&gt;
						12 Sep, 2026					&lt;/div&gt;
													&lt;div&gt;
						&lt;span&gt;
												Latest Posts						&lt;/span&gt;
								&lt;div&gt;
			&lt;div&gt;
									&lt;div&gt;
						&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/&quot;&gt;Immurok Fingerprint Key Unlocks Linux, Approves SSH and AI Agents&lt;/a&gt;
					&lt;/div&gt;
									&lt;div&gt;
						&lt;a href=&quot;https://gadgeteer.co.za/australians-could-soon-opt-out-of-social-media-algorithms-altogether/&quot;&gt;Australians Could Soon Opt Out of Social Media Algorithms Altogether&lt;/a&gt;
					&lt;/div&gt;
									&lt;div&gt;
						&lt;a href=&quot;https://gadgeteer.co.za/i-discovered-kdes-hidden-superpowers-after-installing-these-3-open-source-utilities/&quot;&gt;I discovered KDE’s hidden superpowers after installing these 3 open-source utilities&lt;/a&gt;
					&lt;/div&gt;
									&lt;div&gt;
						&lt;a href=&quot;https://gadgeteer.co.za/kept-is-an-open-source-self-hosted-alternative-to-google-keep-notes/&quot;&gt;Kept is an open-source self-hosted alternative to Google Keep notes&lt;/a&gt;
					&lt;/div&gt;
									&lt;div&gt;
						&lt;a href=&quot;https://gadgeteer.co.za/im-not-dead-yet-reverse-polish-notation-calculators-you-can-still-buy/&quot;&gt;“I’m Not Dead Yet!” Reverse Polish Notation Calculators You Can Still Buy&lt;/a&gt;
					&lt;/div&gt;
							&lt;/div&gt; 
		&lt;/div&gt;
							&lt;/div&gt; 
				
								


			&lt;/div&gt;
		&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;Home&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/blog/&quot;&gt;&lt;span&gt;Blog&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Immurok Fingerprint Key Unlocks Linux, Approves SSH and AI Agents&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;    
	&lt;div&gt;
		&lt;main&gt;

		
			
&lt;article&gt;
	&lt;header&gt;
		&lt;h1&gt;Immurok Fingerprint Key Unlocks Linux, Approves SSH and AI Agents&lt;/h1&gt;		&lt;div&gt;
			&lt;span&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/&quot;&gt;&lt;time&gt;2026-09-12&lt;/time&gt;&lt;time&gt;2026-09-12&lt;/time&gt;&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span&gt;&lt;a href=&quot;https://gadgeteer.co.za/author/wpadmin/&quot;&gt;Danie&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;		&lt;/div&gt;
	&lt;/header&gt;

    &lt;img src=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/&quot; alt=&quot;Finger about to press a small device next to buttons labeled Unlock Screen, Authorize sudo, Confirm System Prompts, Autofill TOTP, Approve AI Agents, and Sign SSH &amp;amp; Git.&quot; title=&quot;Immurok Fingerprint Key Unlocks Linux, Approves SSH and AI Agents 1&quot;/&gt;
	&lt;div&gt;
		&lt;div&gt;
			
&lt;p&gt;“It is a tiny wireless box that can unlock your desktop session, approve a sudo command, authenticate via polkit, log you into a server over SSH, generate TOTP codes for 2FA, and put a physical touch in front of an AI coding agent. And it does all of that with the same finger, over Bluetooth. The good news is that the core features work. The less good news is that on Linux, getting there was not as simple as touching a sensor.”&lt;/p&gt;



&lt;p&gt;So, yes no ready to use graphical interface like Windows, and macOS users get, but it can be setup and got to work, and after that it seems pretty seamless.&lt;/p&gt;



&lt;p&gt;You always have your passwords to fall back to, if you leave your finger behind or lose it somewhere.&lt;/p&gt;



&lt;p&gt;It is a Kickstarter project, but good to see there is a working review unit, so it is not vaporware.&lt;/p&gt;



&lt;p&gt;See &lt;a href=&quot;https://itsfoss.com/immurok-review&quot;&gt;https://itsfoss.com/immurok-review&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;h3&gt;Share this:&lt;/h3&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=twitter&quot;&gt;
				&lt;span&gt;Share on X (Opens in new window)&lt;/span&gt;
				&lt;span&gt;X&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=facebook&quot;&gt;
				&lt;span&gt;Share on Facebook (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Facebook&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=linkedin&quot;&gt;
				&lt;span&gt;Share on LinkedIn (Opens in new window)&lt;/span&gt;
				&lt;span&gt;LinkedIn&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=reddit&quot;&gt;
				&lt;span&gt;Share on Reddit (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Reddit&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;More&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=tumblr&quot;&gt;
				&lt;span&gt;Share on Tumblr (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Tumblr&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=pinterest&quot;&gt;
				&lt;span&gt;Share on Pinterest (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Pinterest&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=telegram&quot;&gt;
				&lt;span&gt;Share on Telegram (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Telegram&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/?share=jetpack-whatsapp&quot;&gt;
				&lt;span&gt;Share on WhatsApp (Opens in new window)&lt;/span&gt;
				&lt;span&gt;WhatsApp&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://gadgeteer.co.za/cdn-cgi/l/email-protection#c6f9b5b3a4aca3a5b2fbe3f38495aea7b4a3a2e3f4f696a9b5b2e3f382e3f4f68fababb3b4a9ade3f4f680afa8a1a3b4b6b4afa8b2e3f4f68da3bfe3f4f693a8aaa9a5adb5e3f4f68aafa8b3bee3f485e3f4f687b6b6b4a9b0a3b5e3f4f695958ee3f4f6a7a8a2e3f4f6878fe3f4f687a1a3a8b2b5e0e5f6f5fefda4a9a2bffbaeb2b2b6b5e3f587e3f480e3f480a1a7a2a1a3b2a3a3b4e8a5a9e8bca7e3f480afababb3b4a9adeba0afa8a1a3b4b6b4afa8b2ebada3bfebb3a8aaa9a5adb5ebaaafa8b3beeba7b6b6b4a9b0a3b5ebb5b5aeeba7a8a2eba7afeba7a1a3a8b2b5e3f480e0e5f6f5fefdb5aea7b4a3fba3aba7afaa&quot;&gt;
				&lt;span&gt;Email a link to a friend (Opens in new window)&lt;/span&gt;
				&lt;span&gt;Email&lt;/span&gt;
			&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Like this:&lt;/h3&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Like&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;Loading…&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;
	&lt;h3&gt;&lt;em&gt;Related&lt;/em&gt;&lt;/h3&gt;
&lt;/div&gt;					&lt;/div&gt;
	&lt;/div&gt;

	&lt;footer&gt;
		&lt;span&gt;&lt;a href=&quot;https://gadgeteer.co.za/blog/&quot;&gt;Blog&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://gadgeteer.co.za/tag/linux-2/&quot;&gt;linux&lt;/a&gt;, &lt;a href=&quot;https://gadgeteer.co.za/tag/security/&quot;&gt;security&lt;/a&gt;, &lt;a href=&quot;https://gadgeteer.co.za/tag/technology/&quot;&gt;technology&lt;/a&gt;&lt;/span&gt;	&lt;/footer&gt;

&lt;/article&gt;

			
	
			
&lt;div&gt;

	
	
	
		&lt;div&gt;
		&lt;h3&gt;Leave a Reply &lt;small&gt;&lt;a href=&quot;https://gadgeteer.co.za/immurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents/#respond&quot;&gt;Cancel reply&lt;/a&gt;&lt;/small&gt;&lt;/h3&gt;&lt;p&gt;You must be &lt;a href=&quot;https://gadgeteer.co.za/wp-login.php?redirect_to=https%3A%2F%2Fgadgeteer.co.za%2Fimmurok-fingerprint-key-unlocks-linux-approves-ssh-and-ai-agents%2F&quot;&gt;logged in&lt;/a&gt; to post a comment.&lt;/p&gt;	&lt;/div&gt;
	&lt;p&gt;This site uses Akismet to reduce spam. &lt;a href=&quot;https://akismet.com/privacy/&quot;&gt;Learn how your comment data is processed.&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

		
		&lt;/main&gt;
	&lt;/div&gt;

&lt;div&gt;
				&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content:encoded>
</item>
<item>
<title>Simon Tatham: &quot;I noticed today that an update to the #Linux #Zoo…&quot; - Hachyderm.io</title>
<link>https://hachyderm.io/@simontatham/117201594980991062</link>
<guid isPermaLink="false">MFONDCkGCoasUSUqw2uiN7ulrGDfr0IwAZt6PQ==</guid>
<pubDate>Sat, 12 Sep 2026 17:53:41 +0000</pubDate>
<description>I noticed today that an update to the #Linux #Zoom client has made it start proactively reading _everything_ written to the X11 clipboard. If you keep interesting secrets in your clipboard – particularly, if a password manager uses it as a means of getting the password to where it needs to be – this might be a thing you need to know about!</description>
<content:encoded>&lt;p&gt;&lt;a href=&quot;https://lobste.rs/s/8t1ddm/linux_zoom_client_proactively_reads_x11&quot;&gt;Comments&lt;/a&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Base84 deserves a place in file names - Frank DENIS random thoughts.</title>
<link>https://00f.net/2026/09/09/base84/</link>
<enclosure type="image/jpeg" length="0" url="https://00f.net/favicon.ico"></enclosure>
<guid isPermaLink="false">WDCWtbGcuQBIUkg4xjmmg8Zs8EtZiOgbTb7ptw==</guid>
<pubDate>Sat, 12 Sep 2026 17:53:41 +0000</pubDate>
<description>The TurboCrypt file encryption tool was originally designed for Unix systems.</description>
<content:encoded>&lt;p&gt;The &lt;a href=&quot;https://github.com/jedisct1/turbocrypt&quot;&gt;TurboCrypt&lt;/a&gt; file encryption tool was originally designed for Unix systems.&lt;/p&gt;&lt;p&gt;And it used to encrypt file names and encode the resulting ciphertext using Base91.&lt;/p&gt;&lt;p&gt;Why Base91? Because it’s a perfect fit for encrypted file names, producing strings that can be stored as valid files on Unix and macOS.&lt;/p&gt;&lt;p&gt;“But my filesystem can store arbitrary file names”! That may be true for some filesystems, but this is without taking libraries and applications into consideration. For example, the macOS Finder would not like this at all.&lt;/p&gt;&lt;p&gt;So, Base91 worked fine for encrypted file and directory names.&lt;/p&gt;&lt;p&gt;Then people asked for Windows support, where several characters in the Unix filesystem-safe alphabet are forbidden.&lt;/p&gt;&lt;p&gt;So, TurboCrypt is switching to Base84.&lt;/p&gt;&lt;p&gt;Something surprisingly not defined nor (apparently) used anywhere, even though it’s a perfect fit for anything that should be encoded as portable filesystem-safe names.&lt;/p&gt;&lt;h2&gt;Why Base84?&lt;/h2&gt;&lt;p&gt;There are 94 printable ASCII characters excluding the space. But Windows rules exclude nine of them:&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&amp;lt; &amp;gt; : &amp;quot; / \ | ? *&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;That leaves 85.&lt;/p&gt;&lt;p&gt;But a name ending in a dot doesn’t work reliably through the Windows shell and ordinary file APIs.&lt;/p&gt;&lt;p&gt;Remove the dot as well, and we have 84 characters that can appear anywhere in a filename component. &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file&quot;&gt;Microsoft documents these restrictions&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;However, Windows allows a leading dot: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; is fine.&lt;/p&gt;&lt;p&gt;But dropping dots also avoids hidden names on Unix and the special names &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;..&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Here’s the alphabet, in encoding order:&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&amp;amp;&amp;#39;()+,-;=@[]^_`{}~&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Every character is acceptable in a filename on the usual Linux, macOS and Windows filesystems.&lt;/p&gt;&lt;h2&gt;Packing the bits&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/jedisct1/zig-base84&quot;&gt;zig-base84&lt;/a&gt; is an implementation of Base84.&lt;/p&gt;&lt;p&gt;It emits groups of five characters. Five is the sweet spot: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;84⁵ = 4,182,119,424&lt;/code&gt;, only 2.6% short of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2³²&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;That leaves enough room for a group to hold 32 bits about 95% of the time on uniformly random input, and 31 bits otherwise.&lt;/p&gt;&lt;p&gt;The encoder looks at the next 31 bits. If their value is below &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;84⁵ - 2³¹&lt;/code&gt;, there’s room for a 32nd bit. Otherwise, it consumes just those 31 bits. Either way, the value fits in five base-84 digits.&lt;/p&gt;&lt;p&gt;On random input, that’s about 31.95 bits per group, or 6.39 bits per character. The output is about 25.2% larger than the binary input. Almost Base85.&lt;/p&gt;&lt;p&gt;These expansion rates ignore the final partial group; the averages assume random input:&lt;/p&gt;&lt;p&gt;An input filled with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xff&lt;/code&gt; forces every full group to consume only 31 bits. That’s the worst case: about 29% expansion.&lt;/p&gt;&lt;p&gt;Most filesystems cap a name at 255 bytes. Since the alphabet is ASCII, that’s 255 characters. Five divides 255 exactly, so even a maximum-length name holds only complete groups, with no bits lost to a partial one. Base84 guarantees room for 197 bytes of input, compared with 191 for unpadded Base64.&lt;/p&gt;&lt;h2&gt;Unix-only names&lt;/h2&gt;&lt;p&gt;Unix filenames can contain most of the punctuation Windows rejects. NUL and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; are forbidden inside a filename; the &lt;a href=&quot;https://www.man7.org/linux/man-pages/man7/pathname.7.html&quot;&gt;Linux pathname documentation&lt;/a&gt; lists the rules and filesystem-specific limits.&lt;/p&gt;&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filesystem&lt;/code&gt; variant in &lt;a href=&quot;https://github.com/jedisct1/zig-base91&quot;&gt;zig-base91&lt;/a&gt; replaces the standard Base91 alphabet’s slash with an apostrophe. It packs about 6.51 bits per character on random input, giving roughly 23% expansion.&lt;/p&gt;&lt;p&gt;For Unix-only names, use that variant. Standard Base91 still contains &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;, and both alphabets contain characters Windows rejects.&lt;/p&gt;&lt;h2&gt;Reserved names and case&lt;/h2&gt;&lt;p&gt;Windows reserves device names such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CON&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NUL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COM1&lt;/code&gt;, regardless of case.&lt;/p&gt;&lt;p&gt;The five-character packing has a useful side effect: with the standard alphabet, the encoder can’t spell a reserved device name, even for short inputs.&lt;/p&gt;&lt;p&gt;A three-character output always ends with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;J&lt;/code&gt;. That rules out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CON&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRN&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AUX&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NUL&lt;/code&gt;, regardless of case.&lt;/p&gt;&lt;p&gt;A four-character output always ends with an uppercase letter or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;. It can’t end with a digit, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COM1&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COM9&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LPT1&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LPT9&lt;/code&gt; are impossible too. The superscript digits Windows also reserves aren’t in the alphabet.&lt;/p&gt;&lt;p&gt;And the alphabet has no dots, so a reserved name followed by an extension is also impossible.&lt;/p&gt;&lt;p&gt;No padding or special handling is needed to avoid these names.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>CSF Security Advisory September 2026: Critical Vulnerability and Patch Guide</title>
<link>https://www.seekahost.in/csf-security-advisory-critical-patch/</link>
<enclosure type="image/jpeg" length="0" url="https://www.seekahost.in/wp-content/uploads/2026/09/CSF-Security-Advisory-Critical-Vulnerability-Patch.png"></enclosure>
<guid isPermaLink="false">1X37tJoa7_qP2aUXv1Qr5Tx-oRZWCQdoZrBYpQ==</guid>
<pubDate>Sat, 12 Sep 2026 17:00:35 +0000</pubDate>
<description>There is a new CVE vulnerability affecting CSF. Find its security impact, affected versions, and how to update ConfigServer Firewall to version 16.31 or later.</description>
<content:encoded>&lt;div&gt;&lt;div&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/01/seekahost-india-logo-bl.png&quot; alt=&quot;SeekaHost Logo&quot; title=&quot;&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;Domains&lt;/h3&gt;&lt;hr/&gt;&lt;div&gt;&lt;a href=&quot;https://www.google.com/search?q=seekahost+india#lrd=0x3ba8ff9dc12f88df:0xd63c08688b83697d,1,,,&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.trustpilot.com/review/seekahost.in&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;Domains&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/register-domain&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-16-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-16-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Register a Domain&lt;span&gt;Hype&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Secure your perfect domain.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/domain-transfer&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-17-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-17-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Transfer Domains&lt;/span&gt;&lt;span&gt;Move your domain with ease.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/domain-price&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-15-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-15-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Domain Pricing&lt;/span&gt;&lt;span&gt;Explore pricing across extensions.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Online Essentials&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/ssl-certificate&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-3-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-3-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;SSL Certificate&lt;span&gt;Safe&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Secure websites with encryption.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/email-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-34-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-34-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;E-Mail Hosting&lt;span&gt;Professional&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Professional email for your business.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;AI Tools&lt;/h4&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/ai-domain-name-generator/&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;AI Domain Name Generator&lt;span&gt;Live Now&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Try Hynts - domain ideas nobody has taken&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Business Name Checker&lt;span&gt;Live on Sep 16&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Check names for your business.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/register-domain&quot;&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-Panel-2.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Take Your Name&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/register-domain&quot;&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-Panel-2.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Take Your Name&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;Hosting&lt;/h3&gt;&lt;hr/&gt;&lt;div&gt;&lt;a href=&quot;https://www.google.com/search?q=seekahost+india#lrd=0x3ba8ff9dc12f88df:0xd63c08688b83697d,1,,,&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.trustpilot.com/review/seekahost.in&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;Website Hosting&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/web-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-4-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-4-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Web Hosting&lt;/span&gt;&lt;span&gt;Reliable hosting for every website.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/business-web-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-5-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-5-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Business Hosting&lt;span&gt;Hot&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Powerful hosting for growing businesses.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/wordpress-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Wordpress-Hosting-Icon-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Wordpress-Hosting-Icon-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;WordPress Hosting&lt;span&gt;Hype&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Optimized hosting for WordPress websites.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/woocommerce-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/WooCommerce-Hosting-Icon-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Woocommerce-White-Logo.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;WooCommerce Hosting&lt;/span&gt;&lt;span&gt;Fast hosting for online stores.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/magento-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Magento-Hosting-Icon-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Magento-Hosting-Icon-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Magento Hosting&lt;/span&gt;&lt;span&gt;Powerful hosting for Magento commerce.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Adaptive-Core-Security-Suite-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Adaptive-Core-Security-Suite-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Adaptive Core Security Suite&lt;/span&gt;&lt;span&gt;Safeguarding Your Website 24/7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Servers&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/vps-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-6-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-6-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;VPS Hosting&lt;/span&gt;&lt;span&gt;Flexible virtual server resources.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/dedicated-server-india&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Dedicated-Server-Logo-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Dedicated-Server-Logo-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Dedicated Hosting&lt;/span&gt;&lt;span&gt;Powerful dedicated physical servers.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/n8n-self-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/n8n-Icon-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/n8n-Icon-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n8n Self Hosted&lt;span&gt;Trend&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Self-hosted workflow automation platform.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Panel Hosting&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/cpanel-web-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-7-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-7-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cPanel Hosting&lt;/span&gt;&lt;span&gt;Easy hosting with cPanel.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/plesk-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-10-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-10-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Plesk Hosting&lt;/span&gt;&lt;span&gt;Simple hosting with Plesk.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/litespeed-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-8-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-8-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;LiteSpeed Hosting&lt;span&gt;Hot&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Faster hosting powered by LiteSpeed.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/reseller-hosting&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-9-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-9-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Reseller Hosting&lt;span&gt;Hype&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Launch your own hosting business.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;AI Tools&lt;/h4&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/ai-domain-name-generator/&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;AI Domain Name Generator&lt;span&gt;Live Now&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Try Hynts - domain ideas nobody has taken&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Business Name Checker&lt;span&gt;Live on Sep 16&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Check names for your business.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/web-hosting&quot;&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-1.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Explore Hosting&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/vps-hosting&quot;&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-1.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Launch Servers&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/cpanel-web-hosting&quot;&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-1.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Explore Panels&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;About&lt;/h3&gt;&lt;hr/&gt;&lt;div&gt;&lt;a href=&quot;https://www.google.com/search?q=seekahost+india#lrd=0x3ba8ff9dc12f88df:0xd63c08688b83697d,1,,,&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Google-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.trustpilot.com/review/seekahost.in&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-icon.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Excellent&lt;/span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Trustpilot-Review-Stars.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;4.9 Reviews&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h3&gt;Learn&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/blog&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-22-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-22-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Blog&lt;/span&gt;&lt;span&gt;Hosting insights, tips, and updates.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.youtube.com/@seekahostindia&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-24-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-24-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Tutorials&lt;/span&gt;&lt;span&gt;Step-by-step website hosting guides.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/category/web-hosting/&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-23-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-23-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Hosting Guides&lt;/span&gt;&lt;span&gt;Learn hosting from basics.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Support&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://portal.seekahost.in/index.php/knowledgebase&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-27-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-27-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Knowledge Base&lt;/span&gt;&lt;span&gt;Find answers and solutions.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://portal.seekahost.in/submitticket.php&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-26-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-26-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Submit a Ticket&lt;/span&gt;&lt;span&gt;Request technical support assistance.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-25-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-25-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Server Status&lt;span&gt;Live&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Check current service availability.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Company&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/about-us/&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-33-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-33-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;About Us&lt;/span&gt;&lt;span&gt;Discover our story and mission.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/contact-us&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-31-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-31-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Contact Us&lt;/span&gt;&lt;span&gt;Get in touch with us.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://portal.seekahost.in/affiliates.php&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-28-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-28-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Affiliate Program&lt;/span&gt;&lt;span&gt;Partner with us and earn.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/reviews&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-32-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-32-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Reviews&lt;/span&gt;&lt;span&gt;See what our customers say.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.seekahost.in/branding&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-30-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-30-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Branding&lt;/span&gt;&lt;span&gt;Explore our brand and identity.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://portal.seekahost.in/index.php/announcements&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-29-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-29-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Announcements&lt;span&gt;New&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Stay updated with latest news.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;AI Tools&lt;/h4&gt;&lt;div&gt;&lt;div&gt;&lt;a href=&quot;https://www.seekahost.in/ai-domain-name-generator/&quot;&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-13-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;AI Domain Name Generator&lt;span&gt;Live Now&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Try Hynts - domain ideas nobody has taken&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-Black.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Icon-14-White.svg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Business Name Checker&lt;span&gt;Live on Sep 16&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Check names for your business.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-Panel-3.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Expert Care&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-Panel-3.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Expert Care&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;img src=&quot;https://www.seekahost.in/wp-content/uploads/2026/08/Mega-menu-Panel-3.webp&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;span&gt;Expert Care&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://portal.seekahost.in/clientarea.php&quot;&gt;User Login &lt;/a&gt;&lt;/div&gt;</content:encoded>
</item>
<item>
<title>Discord Screen Share Broken on KDE Wayland? Here&#39;s the fix</title>
<link>https://oxal.org/blog/discord-screen-share-broken-kde-wayland/</link>
<guid isPermaLink="false">NgVaqcPSGUNcyb0FI162C9yUsBBtfFrYs4xpdg==</guid>
<pubDate>Sat, 12 Sep 2026 04:48:56 +0000</pubDate>
<description>So I’m in a call, someone asks me to share my screen, I click the button and… nothing. No error, no dialog, no nothing. Just Discord pretending I never clicked anything. Cool cool cool. I...</description>
<content:encoded>&lt;p&gt;So I’m in a call, someone asks me to share my screen, I click the button and… nothing. No error, no dialog, no nothing. Just Discord pretending I never clicked anything. Cool cool cool.&lt;/p&gt;&lt;p&gt;I’m on KDE Plasma + Wayland. And oh, Arch btw (CachyOS specifically). Running the native &lt;code&gt;discord&lt;/code&gt; package from pacman. Everything was working perfectly fine like two days ago. What changed? No idea. Something crashed silently. “It just works” said no linux user ever. 🙃&lt;/p&gt;&lt;h2&gt;How screen sharing even works on Wayland&lt;/h2&gt;&lt;p&gt;Okay so on Wayland, screen sharing goes through this whole chain:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Discord (Electron) → xdg-desktop-portal → KDE portal backend → PipeWire → your screen&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Discord asks the portal “hey can I see the screen?”, the portal asks your desktop environment’s backend to handle it, and that backend uses PipeWire to actually grab the pixels. It’s a lot of moving parts. But it works.&lt;/p&gt;&lt;h2&gt;The debugging rabbit hole&lt;/h2&gt;&lt;p&gt;First thing I checked: are the right Electron flags set? On Wayland, Discord needs these or it won’t even try the proper screen capture path:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;discord --enable-features=UseOzonePlatform,WebRTCPipeWireCapturer --ozone-platform=wayland&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(These go in your &lt;code&gt;.desktop&lt;/code&gt; file’s &lt;code&gt;Exec=&lt;/code&gt; line. If you haven’t done this already, do it now.)&lt;/p&gt;&lt;p&gt;But that wasn’t it. I already had these set. Screen share was still completely dead.&lt;/p&gt;&lt;p&gt;So I dug deeper. Is the &lt;code&gt;ScreenCast&lt;/code&gt; portal interface even available?&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ dbus-send --session \
    --dest=org.freedesktop.portal.Desktop \
    --type=method_call --print-reply \
    /org/freedesktop/portal/desktop \
    org.freedesktop.DBus.Properties.Get \
    string:org.freedesktop.portal.ScreenCast \
    string:version
Error org.freedesktop.DBus.Error.InvalidArgs: No such interface &amp;quot;org.freedesktop.portal.ScreenCast&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;No &lt;code&gt;ScreenCast&lt;/code&gt; interface. At all. There it is. The portal literally has no backend that knows how to capture screens. No wonder Discord was doing nothing — there was nothing to do.&lt;/p&gt;&lt;h2&gt;The actual problem&lt;/h2&gt;&lt;p&gt;Wanna guess?&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ systemctl --user status plasma-xdg-desktop-portal-kde.service
○ plasma-xdg-desktop-portal-kde.service - Xdg Desktop Portal For KDE
     Active: inactive (dead)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Dead. The KDE portal backend was just… dead. This is the service that provides &lt;code&gt;ScreenCast&lt;/code&gt;, &lt;code&gt;Screenshot&lt;/code&gt;, &lt;code&gt;RemoteDesktop&lt;/code&gt; — basically everything screen-related on KDE Plasma. Without it, the only portal running was the GTK one, which doesn’t provide &lt;code&gt;ScreenCast&lt;/code&gt; on a KDE session (why would it).&lt;/p&gt;&lt;p&gt;So Discord asks to share screen, the portal goes “I don’t know how to do that”, and Discord goes “okay nevermind” without telling you anything. Super helpful error handling there 🤣&lt;/p&gt;&lt;h2&gt;The fix (it’s two commands)&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;systemctl --user start plasma-xdg-desktop-portal-kde.service
systemctl --user restart xdg-desktop-portal.service&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Start the KDE backend, then restart the main portal so it picks up the new backend. You can verify it worked:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ dbus-send --session \
    --dest=org.freedesktop.portal.Desktop \
    --type=method_call --print-reply \
    /org/freedesktop/portal/desktop \
    org.freedesktop.DBus.Properties.Get \
    string:org.freedesktop.portal.ScreenCast \
    string:version
variant    uint32 5&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Restart Discord after this. You should get the KDE screen picker dialog when you try to share. 🎉&lt;/p&gt;&lt;h2&gt;But why did it die in the first place?&lt;/h2&gt;&lt;p&gt;Here’s the annoying part — &lt;code&gt;plasma-xdg-desktop-portal-kde&lt;/code&gt; is a static systemd unit. It doesn’t auto-restart on crash. Your Plasma session starts it once when you log in, and if it crashes mid-session (OOM, random segfault, who knows), it just stays dead. You just lose screen sharing until you notice and manually restart it, or log out and back in.&lt;/p&gt;&lt;p&gt;If this keeps happening to you, check the logs next time:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;journalctl --user -u plasma-xdg-desktop-portal-kde&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Maybe there’s a pattern. Maybe something is killing it. I haven’t figured that part out yet (added to my infinitely long todo list).&lt;/p&gt;&lt;h2&gt;TL;DR&lt;/h2&gt;&lt;p&gt;Discord screen share broken on KDE Wayland? Run &lt;code&gt;systemctl --user status plasma-xdg-desktop-portal-kde.service&lt;/code&gt;. It’s probably dead. Start it, restart &lt;code&gt;xdg-desktop-portal&lt;/code&gt;, restart Discord. Done.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Power grab</title>
<link>https://tante.cc/2026/09/11/power-grab/</link>
<enclosure type="image/jpeg" length="0" url="https://tante.cc/wp-content/uploads/2026/09/ivtcn1h4x1k.jpg"></enclosure>
<guid isPermaLink="false">0bgQPgKvSrV3reJkGxF9zVRvMqZrWIPvnBvQTg==</guid>
<pubDate>Sat, 12 Sep 2026 02:21:37 +0000</pubDate>
<description>Omarchy should not matter. But sadly it does. As a power grab. If you don’t know what Omarchy is here’s the short summary. David Heinemeier Hansson, creator of RubyOnRails, owner of a software business and millionaire, decided a few months ago to go all in on Linux and – because that’s just his MO – […]</description>
<content:encoded>&lt;p&gt;Omarchy should not matter. But sadly it does. As a power grab.&lt;/p&gt;&lt;p&gt;If you don’t know what Omarchy is here’s the short summary. &lt;a href=&quot;https://en.wikipedia.org/wiki/David_Heinemeier_Hansson&quot;&gt;David Heinemeier Hansson&lt;/a&gt;, creator of RubyOnRails, owner of a software business and millionaire, decided a few months ago to go all in on Linux and – because that’s just his MO – thought that turning his setup into a project made sense. Omarchy is just that: A pretty standard Arch Linux distribution with a handful of configuration files, that Heinemeier Hansson (or DHH as he is often called) wrote, or vibed or whatever. There is nothing wrong with this, custom, opinionated special purpose distributions have been part of the Linux culture for a long time and provide a lot of value and experimentation that sometimes even flows back to the original project. In a way Ubuntu Linux is just that to the basis Debian.&lt;/p&gt;&lt;p&gt;There’s also nothing wrong in more opinionated software – quite the opposite. I do think that RubyOnRails and similar frameworks gained traction especially because they do have a clear idea of how they see the respective problem domain. There’s even the statement “There should be one – and preferably only one – obvious way to do it” in the &lt;a href=&quot;https://peps.python.org/pep-0020/&quot;&gt;Zen of Python&lt;/a&gt;. Having a strong point of view is not a bad thing in software or in general. The problem is the kind of points of view DHH has.&lt;/p&gt;&lt;p&gt;I don’t want to go into all the gritty details here, Brennan Kenneth Brown did a great job with their article “&lt;a href=&quot;https://brennan.day/normalized-fascism-in-open-source-12-million-given-to-dhh/&quot;&gt;Normalized Fascism in Open Source: $12 Million Given to DHH&lt;/a&gt;“, but here’s the short version. DHH is a racist and a fascist. He recently wrote articles on how there are [Content Warning: massive racism] &lt;a href=&quot;https://web.archive.org/web/20250925050154/https://world.hey.com/dhh/as-i-remember-london-e7d38e64&quot;&gt;too many brown people in London these days&lt;/a&gt;. In July he wrote an [Content Warning: Racism, anti-romanism] &lt;a href=&quot;https://web.archive.org/web/20260721200429/https:/world.hey.com/dhh/wolves-sheep-and-gypsies-ba44af6a&quot;&gt;article&lt;/a&gt; comparing Roma communities (using a slur for them) to “wolves” that should be “shot”. &lt;a href=&quot;https://x.com/dhh?lang=en&quot;&gt;His X account&lt;/a&gt; is also know to be “edgy” in a similar way. A few days ago he posted &lt;a href=&quot;https://x.com/dhh/status/2098043643395277095&quot;&gt;sort of a manifesto&lt;/a&gt; for his set of config files:&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://tante.cc/wp-content/uploads/2026/09/Screenshot-2026-09-11-at-13.26.57-1200x1484.png&quot; alt=&quot;Screenshot of an X post (url: https://x.com/dhh/status/2098043643395277095) from the account @dhh saying:
Unite the nerds
Hold the line
Have some fun
Beauty is truth
Heritage is duty
Command is service
Welcome the agents
Perfect the computer
Own the machine
You’re somebody now
&quot; title=&quot;&quot;/&gt;&lt;/figure&gt;&lt;p&gt;There’s even a &lt;a href=&quot;https://omarchy.org/doctrine/&quot;&gt;longer version on the website&lt;/a&gt;. Even without a strong background in antifascist literature or history this reads like a fascist creed. About unity and identity. About “holding the line” (against codes of conduct and the rights of marginalized people as the website explains). About how there always needs to be a strong leader who makes the decisions. Given DHH’s other writing this is &lt;em&gt;not&lt;/em&gt; a misguided joke, this is how he thinks about the world.&lt;/p&gt;&lt;p&gt;I began this text writing “Omarchy should not matter” but I have not explained why it does. It’s surely not about user numbers (it’s a clunky distro aimed at people who love to cosplay hackers). But it is about power.&lt;/p&gt;&lt;p&gt;DHH has used his connection to CEO’s of tech corporations and his position as influencer to collect up to now above 18 million dollars of funding for Omarchy. He uses that money not for himself (he has enough of that) but to fund certain pieces of Software he uses in his distribution. Like for example the window manager hyprland whose &lt;a href=&quot;https://omarchy.org/news/2026/08/omacom-foundation-to-be-exclusive-hyprland-sponsor/&quot;&gt;main developer the Omarchy money now funds&lt;/a&gt;. What is “Vaxry” known for outside of a niche window manager? He runs a community based around LGBTQ discrimination and participates in that (see the short summary on Drew DeVault’s “&lt;a href=&quot;https://drewdevault.com/weird-guys/&quot;&gt;Weird Little Guys of FOSS&lt;/a&gt;” list). His bigotry is so consistent that he was banned from participating in the Freedesktop.org community where all the other developers of window managers and the free software desktop stack collaborate. And it was long before DHH funded him. &lt;/p&gt;&lt;p&gt;One could see a world where a CEO using his connections to drum up some funding for free software projects would be a good thing. But that’s not the world we live in I am afraid. DHH got 3 million USD from Digital Ocean (a cloud provider) for Omarchy. Basically at the same time where Digital Ocean cancelled their support of Flathub and GNOME that amounted to a &lt;a href=&quot;https://social.treehouse.systems/@barthalion/117241534134006167&quot;&gt;value of 50 USD per month&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;DHH is using his position and his influence to accumulate donations that he then can distribute to projects that align with his fascist worldview and ambitions. And in a time where many important projects and infrastructures are strapped for cash running just on the goodwill of a handful of people that is increasingly dangerous. Not because its corporate money – a lot of funding for open source comes from corporations, they are after all who are sucking up all the surplus from people’s labor. &lt;em&gt;It’s because this amount of money gives him power&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;The Omarchy foundation will be where projects in desperate need of funding will be pointed. And will a project focused on human rights and social justice get funding from our fascist overlord? What kind of pressure can that exert on projects who have to decide to either die due to lack of funding or kill their code of conduct? &lt;/p&gt;&lt;p&gt;An open fascist is building one of the bigger sources of funding for open source fully under his individual control and sucks up a lot of money that otherwise might have gone to liberatory projects. Community projects. Antifascist projects. &lt;/p&gt;&lt;p&gt;And that is why Omarchy matters. Sadly. Not because of its technical merit (even though those fascists love to use the “merit” argument to fight human rights) but because of its leader, his connections and his ability to accumulate financial power. Without anyone in that ecosystem saying anything about how that leader operates and talks. And you might know the saying: &lt;em&gt;If there’s a Nazi and 10 folks sitting together at a table and nobody says and does anything? There’s 11 Nazis at that table.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Omarchy got a lot of recognition recently. Not only by corporate donors but by Youtubers and other tech influencers who kept praising it and nudged people (who might not know about DHH’s exploits) towards testing it. To become “a hardcore linux user/dev” or whatever other chauvinist argument they made. This makes it dangerous.&lt;/p&gt;&lt;p&gt;Running Omarchy means contributing to this dynamic. It means willingly integrating oneself into a fascist community. Legitimizing it. Supporting it. &lt;strong&gt;Omarchy is a fascist project that normalizes fascist thinking&lt;/strong&gt; for everyone entering that community (even unknowingly). The baseline has to be not to use that system. And as people who believe in human rights and dignity, in community and a tech world that can be better &lt;strong&gt;we need to oppose Omarchy. Need to make sure it gets no seat at any table&lt;/strong&gt;. &lt;strong&gt;Support projects who actively refuse to collaborate.&lt;/strong&gt; Support projects who care about human rights and flourishing. And &lt;strong&gt;do not do business with the companies who willingly support fascists&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Siamo tutti antifascisti!&lt;/p&gt;&lt;p&gt;&lt;em&gt;(Share this message about Omarchy [or some other similar post] around in the tech circles you frequent. Tell people about the background of this hyped Linux distribution and its fascist leader. Quit your 1password or Digital Ocean accounts and mention that it is because the support fascists.)&lt;/em&gt;&lt;/p&gt;&lt;img src=&quot;https://vg08.met.vgwort.de/na/41fa2317e0764524944696548dc477f9&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;div&gt;&lt;div&gt;Liked it? Take a second to support tante on Patreon!&lt;/div&gt;&lt;a href=&quot;https://www.patreon.com/tante?utm_content=post_button&amp;amp;utm_medium=patron_button_and_widgets_plugin&amp;amp;utm_campaign=78367&amp;amp;utm_term=&amp;amp;utm_source=https://tante.cc/2026/09/11/power-grab/&quot;&gt;&lt;img src=&quot;https://tante.cc/wp-content/plugins/patron-button-and-widgets-by-codebard/images/become_a_patron_button.png&quot; alt=&quot;Become a patron at Patreon!&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0/&quot;&gt;&lt;img src=&quot;https://tante.cc/wp-content/plugins/creative-commons-configurator-1/media/cc/by-sa/4.0/80x15.png&quot; alt=&quot;CC BY-SA 4.0&quot; title=&quot;&quot;/&gt;&lt;/a&gt;
This work is licensed under a &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0/&quot;&gt;Creative Commons Attribution-ShareAlike 4.0 International License&lt;/a&gt;.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>39 distributions Linux populaires | Stackscale</title>
<link>https://www.stackscale.fr/blog/distributions-linux-populaires/</link>
<enclosure type="image/jpeg" length="0" url="https://www.stackscale.fr/wp-content/uploads/2022/02/populaire-Linux-distributies-Stackscale.jpg"></enclosure>
<guid isPermaLink="false">d3v0dbgnbGHYwZXW_3U35-S4Bj2noBN53N2ZTQ==</guid>
<pubDate>Fri, 11 Sep 2026 20:30:23 +0000</pubDate>
<description>We zetten enkele van de populairste Linux-distributies op een rijtje. GNU/Linux-besturingssystemen zijn Unix-achtige open source distributies op basis van de Linux-kernel.</description>
<content:encoded>&lt;p&gt;Une distribution Linux est un système d’exploitation assemblé autour du noyau Linux, accompagné d’un gestionnaire de paquets, d’outils système et, souvent, d’un environnement de bureau. Toutes partagent le même noyau ; ce qui les sépare, ce sont les choix faits autour de lui — le rythme des mises à jour, la politique de support, le modèle de gouvernance et le public visé.&lt;/p&gt;&lt;p&gt;Cette liste rassemble &lt;strong&gt;39 distributions Linux&lt;/strong&gt; et systèmes d’exploitation apparentés, avec leur licence et leur dernière version à jour. Certaines y figurent parce qu’elles dominent le marché ; d’autres, parce qu’elles ont été abandonnées et que la question « est-elle encore maintenue ? » se pose encore. Nous les signalons explicitement plutôt que de les retirer.&lt;/p&gt;&lt;h2&gt;Ubuntu&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Ubuntu&lt;/strong&gt; est une distribution Linux fondée sur Debian, développée par Canonical et une communauté de développeurs. Elle propose trois éditions officielles — &lt;em&gt;Desktop&lt;/em&gt;, &lt;em&gt;Server&lt;/em&gt; et &lt;em&gt;Core&lt;/em&gt; — qui fonctionnent aussi bien sur un poste de travail que sur une machine virtuelle.&lt;/p&gt;&lt;p&gt;C’est la distribution la plus répandue sur les serveurs web et l’une des plus courantes dans les projets cloud, en grande partie grâce à son cycle LTS de cinq ans, extensible avec Ubuntu Pro.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Ubuntu&lt;/strong&gt; : GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version LTS (septembre 2026)&lt;/strong&gt; : Ubuntu 26.04 LTS « Resolute Raccoon », publiée le 23 avril 2026. Ubuntu 24.04 LTS reste prise en charge jusqu’en mai 2029.&lt;/p&gt;&lt;h2&gt;Debian&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Debian&lt;/strong&gt; est un système d’exploitation libre annoncé par Ian Murdock en 1993. Le projet Debian est une communauté de développeurs et d’utilisateurs qui maintient le système GNU à partir de logiciels libres.&lt;/p&gt;&lt;p&gt;Sa réputation de stabilité en fait la base d’un grand nombre d’autres distributions, Ubuntu comprise, et un choix fréquent pour les serveurs de production.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Debian&lt;/strong&gt; : BSD, GPL et autres licences libres.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Debian 13 « Trixie », publiée le 9 août 2025 ; version corrective actuelle 13.6.&lt;/p&gt;&lt;h2&gt;CentOS Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;CentOS Linux&lt;/strong&gt; était une distribution construite à partir du code source de Red Hat Enterprise Linux. Lancée en 2004, elle offrait une compatibilité RHEL sans coût de licence et s’est imposée dans de nombreux parcs de serveurs.&lt;/p&gt;&lt;p&gt;En 2019, Red Hat a annoncé son remplacement par CentOS Stream, ce qui a donné naissance à de nouvelles alternatives open source comme Rocky Linux et AlmaLinux.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de CentOS Linux&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Projet abandonné&lt;/strong&gt; : CentOS Linux 8 a atteint sa fin de vie le 31 décembre 2021 et CentOS Linux 7 le 30 juin 2024. Il n’existe pas de successeur sous ce nom — les alternatives sont AlmaLinux, Rocky Linux ou CentOS Stream.&lt;/p&gt;&lt;h2&gt;CentOS Stream&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.centos.org/centos-stream/&quot;&gt;&lt;strong&gt;CentOS Stream&lt;/strong&gt;&lt;/a&gt; est une plateforme de développement en amont de Red Hat Enterprise Linux : elle reçoit les changements avant qu’ils n’arrivent dans RHEL, au lieu de les répliquer après coup.&lt;/p&gt;&lt;p&gt;Ce positionnement en fait un environnement utile pour anticiper les évolutions de RHEL, mais un choix différent d’un clone stable pour de la production classique.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de CentOS Stream&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : CentOS Stream 10, publiée le 12 décembre 2024 et prise en charge jusqu’en mai 2030. CentOS Stream 9 l’est jusqu’en mai 2027.&lt;/p&gt;&lt;h2&gt;Red Hat Enterprise Linux (RHEL)&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.redhat.com/fr/technologies/linux-platforms/enterprise-linux&quot;&gt;&lt;strong&gt;Red Hat Enterprise Linux&lt;/strong&gt;&lt;/a&gt; est la distribution commerciale de Red Hat, disponible en versions serveur et poste de travail. Elle repose sur des logiciels libres mais son abonnement couvre le support, la certification matérielle et les correctifs de sécurité à long terme.&lt;/p&gt;&lt;p&gt;C’est la référence du Linux d’entreprise, en particulier dans les secteurs où la certification des applications tierces est une contrainte.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Red Hat Enterprise Linux (RHEL)&lt;/strong&gt; : GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : RHEL 10, publiée le 20 mai 2025 ; versions mineures en cours 10.2 et 9.8.&lt;/p&gt;&lt;h2&gt;Gentoo&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Gentoo&lt;/strong&gt; est une distribution en compilation depuis les sources, à travers son système de paquets Portage. L’utilisateur choisit les options de compilation de chaque composant, ce qui permet d’ajuster finement le système au matériel et à l’usage.&lt;/p&gt;&lt;p&gt;En contrepartie, l’installation et la maintenance demandent nettement plus de temps que sur une distribution binaire.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Gentoo&lt;/strong&gt; : logiciel libre.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Publication&lt;/strong&gt; : &lt;em&gt;rolling release&lt;/em&gt;, sans versions numérotées.&lt;/p&gt;&lt;h2&gt;Fedora&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Fedora&lt;/strong&gt; est la distribution communautaire soutenue par Red Hat. Elle sert de terrain d’essai aux technologies qui arriveront plus tard dans RHEL, avec un cycle court et une politique stricte de logiciel libre.&lt;/p&gt;&lt;p&gt;Chaque version est prise en charge environ treize mois, ce qui en fait un système d’innovation plutôt qu’un système de production longue durée.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Fedora&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Fedora Linux 44, publiée le 28 avril 2026.&lt;/p&gt;&lt;h2&gt;openSUSE&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;openSUSE&lt;/strong&gt; est le projet communautaire parrainé par SUSE. Il propose deux approches : &lt;em&gt;Leap&lt;/em&gt;, une version stable alignée sur SUSE Linux Enterprise, et &lt;em&gt;Tumbleweed&lt;/em&gt;, une &lt;em&gt;rolling release&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Son outil d’administration YaST et son système d’instantanés Btrfs avec retour arrière sont deux de ses signes distinctifs, même si Leap 16 a abandonné YaST.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’openSUSE&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : openSUSE Leap 16.0, publiée le 1er octobre 2025.&lt;/p&gt;&lt;h2&gt;Scientific Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Scientific Linux&lt;/strong&gt; était une distribution fondée sur RHEL et produite par le Fermilab, avec la participation du CERN, de DESY et de l’ETH Zurich, pour les besoins de calcul scientifique.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Scientific Linux&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Projet abandonné&lt;/strong&gt; : Scientific Linux 7 a atteint sa fin de vie le 30 juin 2024. Le Fermilab recommande de migrer vers AlmaLinux ou CentOS Stream.&lt;/p&gt;&lt;h2&gt;CloudLinux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;CloudLinux&lt;/strong&gt; est une distribution commerciale destinée aux hébergeurs mutualisés. Sa technologie LVE isole les ressources de chaque compte, de sorte qu’un site qui consomme trop n’affecte pas les autres du même serveur.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de CloudLinux&lt;/strong&gt; : GPL et licences propriétaires.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : CloudLinux OS 10.2, publiée le 26 mai 2026. Depuis la série 10, elle s’installe par-dessus AlmaLinux au moyen de &lt;em&gt;cldeploy&lt;/em&gt;, sans image d’installation propre.&lt;/p&gt;&lt;h2&gt;elementary OS&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;elementary OS&lt;/strong&gt; est une distribution fondée sur Ubuntu LTS, centrée sur la cohérence visuelle et la simplicité. Son environnement de bureau Pantheon et son modèle de paiement libre pour les applications en font l’une des propositions les plus soignées du Linux grand public.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’elementary OS&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : elementary OS 8.1.1 « Circe », publiée le 27 février 2026.&lt;/p&gt;&lt;h2&gt;Linux Mint&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Linux Mint&lt;/strong&gt; est une distribution fondée sur Ubuntu, souvent recommandée pour la migration depuis Windows grâce à son environnement Cinnamon et à un ensemble d’outils propres particulièrement aboutis.&lt;/p&gt;&lt;p&gt;Le projet maintient également LMDE, une variante bâtie directement sur Debian.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Linux Mint&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Linux Mint 22.3 « Zena », publiée le 11 janvier 2026 et prise en charge jusqu’en avril 2029.&lt;/p&gt;&lt;h2&gt;Arch Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Arch Linux&lt;/strong&gt; suit le principe KISS : une base minimale que l’utilisateur construit lui-même, sans couches d’abstraction. Son gestionnaire de paquets pacman et le dépôt communautaire AUR donnent accès à un catalogue logiciel très large.&lt;/p&gt;&lt;p&gt;Sa documentation, l’Arch Wiki, est une référence utilisée bien au-delà de la distribution elle-même.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Arch Linux&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Publication&lt;/strong&gt; : &lt;em&gt;rolling release&lt;/em&gt;. L’image d’installation est publiée chaque mois.&lt;/p&gt;&lt;h2&gt;Manjaro&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Manjaro&lt;/strong&gt; repose sur Arch Linux mais introduit un délai de validation des paquets et un installateur graphique, ce qui adoucit considérablement la courbe d’entrée tout en conservant l’accès à l’AUR.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Manjaro&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Manjaro 26.1, publiée en août 2026.&lt;/p&gt;&lt;h2&gt;Oracle Linux&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.oracle.com/fr/linux/&quot;&gt;&lt;strong&gt;Oracle Linux&lt;/strong&gt;&lt;/a&gt; est une distribution compatible RHEL distribuée gratuitement, avec un support commercial optionnel. Elle propose son propre noyau optimisé, l’Unbreakable Enterprise Kernel, en plus du noyau compatible Red Hat.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Oracle Linux&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Oracle Linux 10, publiée en juin 2025 ; mise à jour actuelle 10.2.&lt;/p&gt;&lt;h2&gt;Slackware&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Slackware&lt;/strong&gt; est la plus ancienne distribution encore maintenue, créée en 1993 à partir du Softlanding Linux System. Elle revendique la simplicité au sens Unix du terme : peu d’outils d’automatisation, une configuration en fichiers texte et très peu de modifications par rapport aux logiciels d’origine.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Slackware&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Slackware 15.0, publiée le 3 février 2022 et toujours la version stable en vigueur.&lt;/p&gt;&lt;h2&gt;Mageia&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.mageia.org/fr/&quot;&gt;&lt;strong&gt;Mageia&lt;/strong&gt;&lt;/a&gt; est un système de type Unix né en 2010 d’un &lt;em&gt;fork&lt;/em&gt; de Mandriva Linux, créé par d’anciens salariés de Mandriva S.A. et des membres de sa communauté. Le projet met en avant la stabilité et une gouvernance associative.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Mageia&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Mageia 10, publiée le 29 juin 2026.&lt;/p&gt;&lt;h2&gt;Clear Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Clear Linux OS&lt;/strong&gt; était une distribution développée par Intel et optimisée pour ses propres processeurs, connue pour ses performances dans les tests de référence et pour son modèle de &lt;em&gt;bundles&lt;/em&gt; à la place des paquets classiques.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Clear Linux&lt;/strong&gt; : GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Projet abandonné&lt;/strong&gt; : le 18 juillet 2025, Intel a annoncé la fin de Clear Linux OS. Depuis cette date, il ne reçoit plus ni correctifs de sécurité ni maintenance, et son dépôt a été archivé en lecture seule.&lt;/p&gt;&lt;h2&gt;Rocky Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Rocky Linux&lt;/strong&gt; est né en réponse à l’arrêt de CentOS Linux, sous l’impulsion de Gregory Kurtzer, cofondateur de CentOS. Il vise une compatibilité binaire avec RHEL et est porté par la Rocky Enterprise Software Foundation.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Rocky Linux&lt;/strong&gt; : BSD et autres licences libres.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Rocky Linux 10.2, publiée le 28 mai 2026.&lt;/p&gt;&lt;h2&gt;AlmaLinux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;AlmaLinux OS&lt;/strong&gt; est l’autre grande réponse à l’arrêt de CentOS Linux, portée par une fondation à but non lucratif. Depuis la version 10, le projet a assumé de ne plus être un clone strict de RHEL : il conserve la compatibilité applicative mais réintègre des pilotes retirés en amont et prend en charge du matériel plus ancien.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’AlmaLinux&lt;/strong&gt; : GPLv2 et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : AlmaLinux OS 10.2, publiée le 26 mai 2026.&lt;/p&gt;&lt;h2&gt;Asahi Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Asahi Linux&lt;/strong&gt; est le projet de rétro-ingénierie qui porte Linux sur les Mac à puce Apple Silicon. Il fournit les pilotes graphiques et le travail de bas niveau qu’Apple ne documente pas, et se distribue principalement sous la forme de Fedora Asahi Remix.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Asahi Linux&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Fedora Asahi Remix 44, disponible depuis le 28 avril 2026. Le projet n’est plus en phase alpha.&lt;/p&gt;&lt;h2&gt;Lubuntu&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Lubuntu&lt;/strong&gt; est la variante officielle d’Ubuntu avec l’environnement léger LXQt. Elle vise les machines dont les ressources sont limitées ou les déploiements où l’empreinte du bureau doit rester minimale.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Lubuntu&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Lubuntu 26.04 LTS, publiée le 23 avril 2026.&lt;/p&gt;&lt;h2&gt;SUSE Linux Enterprise&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.suse.com/fr-fr/products/server/&quot;&gt;&lt;strong&gt;SUSE Linux Enterprise Server&lt;/strong&gt;&lt;/a&gt; est la distribution commerciale de SUSE, très implantée dans les environnements SAP et dans l’industrie européenne. Elle mise sur des cycles de vie longs et sur les mises à jour du noyau à chaud.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de SUSE Linux Enterprise&lt;/strong&gt; : GNU GPL et licences propriétaires.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : SUSE Linux Enterprise Server 16, disponible depuis le 4 novembre 2025. Le dernier &lt;em&gt;service pack&lt;/em&gt; de la série 15 est le SP7.&lt;/p&gt;&lt;h2&gt;Knoppix&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.knopper.net/knoppix/&quot;&gt;&lt;strong&gt;Knoppix&lt;/strong&gt;&lt;/a&gt; a été l’une des premières distributions &lt;em&gt;live&lt;/em&gt; à s’exécuter entièrement depuis un CD, sans installation. Elle reste une référence historique pour le diagnostic et la récupération de systèmes.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Knoppix&lt;/strong&gt; : licences de logiciel libre.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version&lt;/strong&gt; : Knoppix 9.2, de 2021. Le projet n’a publié aucune nouveauté depuis.&lt;/p&gt;&lt;h2&gt;VzLinux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;VzLinux&lt;/strong&gt; était une distribution compatible RHEL développée par Virtuozzo, pensée pour les environnements virtualisés et les conteneurs.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de VzLinux&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Projet sans activité&lt;/strong&gt; : aucune version ni annonce n’est recensée après 2021.&lt;/p&gt;&lt;h2&gt;Peppermint OS&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Peppermint OS&lt;/strong&gt; est une distribution légère qui privilégie une base minimale que l’utilisateur complète à sa guise. Le projet maintient aujourd’hui deux branches : l’une sur Debian, l’autre sans &lt;em&gt;systemd&lt;/em&gt;, bâtie sur Devuan.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Peppermint OS&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : le projet ne numérote plus ses versions et publie des images datées. La branche Debian 13 date d’octobre 2025 et la branche Devuan 6, sans &lt;em&gt;systemd&lt;/em&gt;, de juin 2026.&lt;/p&gt;&lt;h2&gt;Zorin OS&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://zorin.com/os/&quot;&gt;&lt;strong&gt;Zorin OS&lt;/strong&gt;&lt;/a&gt; est une distribution fondée sur Ubuntu qui soigne particulièrement la transition depuis Windows et macOS, avec des dispositions de bureau imitant l’une ou l’autre. Elle est développée en Irlande.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Zorin OS&lt;/strong&gt; : logiciel libre.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Zorin OS 18.1, publiée le 15 avril 2026.&lt;/p&gt;&lt;h2&gt;BlackArch Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;BlackArch&lt;/strong&gt; est un dérivé d’Arch Linux orienté sécurité offensive et tests d’intrusion, avec un dépôt de plusieurs milliers d’outils installable par-dessus une installation Arch existante.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de BlackArch Linux&lt;/strong&gt; : licences diverses.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Publication&lt;/strong&gt; : &lt;em&gt;rolling release&lt;/em&gt;, avec un dépôt mis à jour en continu.&lt;/p&gt;&lt;h2&gt;SUSE Liberty Linux&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.suse.com/fr-fr/products/suse-liberty-linux/&quot;&gt;&lt;strong&gt;SUSE Liberty Linux&lt;/strong&gt;&lt;/a&gt; n’était pas une distribution à part entière mais une offre de support : SUSE prenait en charge des installations RHEL ou CentOS existantes, sans migration.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de SUSE Liberty Linux&lt;/strong&gt; : support commercial.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;La marque a disparu&lt;/strong&gt; : SUSE a intégré Liberty Linux dans son offre &lt;em&gt;SUSE Multi-Linux Support&lt;/em&gt;, qui continue d’assurer le support des installations RHEL et CentOS.&lt;/p&gt;&lt;h2&gt;Navy Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Navy Linux&lt;/strong&gt; était une distribution d’entreprise compatible RHEL, apparue elle aussi dans le sillage de l’arrêt de CentOS Linux.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Navy Linux&lt;/strong&gt; : GNU GPL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Projet sans activité&lt;/strong&gt; : la dernière version, Navy Linux 8.6, date de mai 2022.&lt;/p&gt;&lt;h2&gt;Tizen&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Tizen&lt;/strong&gt; est un système fondé sur le noyau Linux, porté par la Linux Foundation et Samsung. On le trouve surtout sur les téléviseurs, les montres connectées et l’électroménager, plus que sur des ordinateurs.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Tizen&lt;/strong&gt; : GPLv2, LGPL, Apache License 2.0, BSD et autres.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Tizen 10.0, présente sur la gamme de téléviseurs Samsung 2026.&lt;/p&gt;&lt;h2&gt;Distributions immuables et orientées conteneurs&lt;/h2&gt;&lt;p&gt;Les distributions ci-dessus sont des systèmes polyvalents. Depuis 2020, une seconde famille s’est développée sur un principe différent : des systèmes à &lt;strong&gt;racine immuable&lt;/strong&gt;, sans gestionnaire de paquets traditionnel, mis à jour de façon atomique et configurés de manière déclarative. On ne les administre pas, on les déploie. Elles soutiennent une grande partie de l’infrastructure de conteneurs actuelle et méritent une section à part.&lt;/p&gt;&lt;h2&gt;Alpine Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Alpine Linux&lt;/strong&gt; est une distribution minimaliste bâtie sur musl libc et BusyBox plutôt que sur la glibc et les GNU coreutils. Ce choix ramène une image de base à quelques mégaoctets, ce qui en a fait le point de départ de fait des images de conteneurs : une grande partie de ce qui tourne aujourd’hui sur Docker et Kubernetes démarre depuis une couche Alpine.&lt;/p&gt;&lt;p&gt;Sa taille et sa surface d’attaque réduite expliquent son adoption, mais musl n’est pas totalement compatible avec la glibc et certaines applications livrées en binaires précompilés demandent des ajustements.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Alpine Linux&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Alpine Linux 3.24, publiée le 9 juin 2026.&lt;/p&gt;&lt;h2&gt;NixOS&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;NixOS&lt;/strong&gt; pousse l’infrastructure as code jusqu’au système d’exploitation lui-même : toute la configuration de la machine — paquets, services, utilisateurs, réseau — est déclarée dans des fichiers, et le système est construit à partir d’eux. Deux machines partageant la même configuration sont identiques, et chaque changement produit une nouvelle génération amorçable.&lt;/p&gt;&lt;p&gt;Revenir sur une mise à jour ratée revient donc à choisir la génération précédente dans le menu de démarrage. C’est la distribution à la courbe d’apprentissage la plus raide de cette liste, mais elle traite la dérive de configuration à la racine.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de NixOS&lt;/strong&gt; : MIT.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : NixOS 26.05 « Yarara », publiée le 30 mai 2026.&lt;/p&gt;&lt;h2&gt;Fedora CoreOS&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://fedoraproject.org/coreos/&quot;&gt;&lt;strong&gt;Fedora CoreOS&lt;/strong&gt;&lt;/a&gt; est un système minimal, immuable et à mise à jour automatique, conçu exclusivement pour exécuter des conteneurs. Le système de fichiers racine est en lecture seule, les mises à jour s’appliquent de façon atomique via rpm-ostree et la configuration initiale se déclare avec Ignition au premier démarrage.&lt;/p&gt;&lt;p&gt;Il succède à Container Linux dans l’écosystème Fedora et sert de laboratoire au modèle d’image que Red Hat a ensuite porté dans RHEL.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Fedora CoreOS&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : flux continu bâti sur Fedora Linux 44. Le projet ne publie pas de versions à support long terme.&lt;/p&gt;&lt;h2&gt;Flatcar Container Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Flatcar Container Linux&lt;/strong&gt; est la continuation ouverte de Container Linux après son arrêt, maintenue comme projet de la CNCF. Elle partage l’approche de Fedora CoreOS — système immuable, sans gestionnaire de paquets, dédié aux conteneurs — mais applique ses mises à jour par partitions A/B : la nouvelle version est écrite sur la partition inactive et activée au redémarrage, de sorte qu’un échec ramène au démarrage précédent.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Flatcar Container Linux&lt;/strong&gt; : Apache License 2.0.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version stable (septembre 2026)&lt;/strong&gt; : Flatcar 4593.2.5, du 13 août 2026.&lt;/p&gt;&lt;h2&gt;Talos Linux&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Talos Linux&lt;/strong&gt; est un système d’exploitation conçu pour une seule chose : être un nœud Kubernetes. Il n’a ni shell, ni SSH, ni gestionnaire de paquets, et s’administre entièrement par une API gRPC authentifiée. Cela supprime d’emblée une bonne part de la surface d’attaque d’un nœud classique et rend la configuration du cluster reproductible par construction.&lt;/p&gt;&lt;p&gt;La contrepartie est la rigidité : on n’ouvre pas une session sur un nœud Talos pour déboguer à la main. Il convient aux clusters durcis et homogènes, pas aux serveurs polyvalents.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Talos Linux&lt;/strong&gt; : Mozilla Public License 2.0.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Talos Linux 1.14.0, du 3 septembre 2026.&lt;/p&gt;&lt;h2&gt;SUSE Linux Micro&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.suse.com/products/micro/&quot;&gt;&lt;strong&gt;SUSE Linux Micro&lt;/strong&gt;&lt;/a&gt; est la proposition immuable de SUSE pour l’&lt;em&gt;edge&lt;/em&gt; et comme hôte de conteneurs. Elle utilise des mises à jour transactionnelles sur Btrfs : chaque changement s’applique dans un instantané distinct qui ne devient le système actif qu’après un redémarrage réussi, avec retour arrière automatique en cas d’échec.&lt;/p&gt;&lt;p&gt;Elle complète le portefeuille de SUSE aux côtés de SUSE Linux Enterprise Server 16 et dispose d’un équivalent communautaire, openSUSE Leap Micro.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de SUSE Linux Micro&lt;/strong&gt; : GNU GPL et autres licences.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : SUSE Linux Micro 6.2.&lt;/p&gt;&lt;h2&gt;Amazon Linux&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/fr/linux/amazon-linux-2023/&quot;&gt;&lt;strong&gt;Amazon Linux&lt;/strong&gt;&lt;/a&gt; est la distribution qu’AWS maintient et optimise pour ses propres instances, avec une intégration directe aux services et aux outils du fournisseur. Amazon Linux 2023 est la génération actuelle, avec une version majeure tous les deux ans et cinq ans de support.&lt;/p&gt;&lt;p&gt;Un point pratique mérite d’être signalé : &lt;strong&gt;Amazon Linux 2 a atteint sa fin de vie le 30 juin 2026&lt;/strong&gt;, de sorte que les charges encore hébergées sur cette version sont aujourd’hui sans support et en attente de migration.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence d’Amazon Linux&lt;/strong&gt; : licence Amazon fondée sur des logiciels open source.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Amazon Linux 2023, prise en charge jusqu’au 30 juin 2029.&lt;/p&gt;&lt;h2&gt;Proxmox VE&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://www.proxmox.com/en/proxmox-virtual-environment/overview&quot;&gt;&lt;strong&gt;Proxmox Virtual Environment&lt;/strong&gt;&lt;/a&gt; n’est pas une distribution polyvalente mais une plateforme de virtualisation bâtie sur Debian, qui combine KVM pour les machines virtuelles et LXC pour les conteneurs système, avec le stockage distribué Ceph et la haute disponibilité intégrés, le tout administré depuis sa propre interface web.&lt;/p&gt;&lt;p&gt;Elle est devenue une référence européenne dans la discussion sur les alternatives ouvertes aux plateformes de virtualisation propriétaires, et sa base Debian garde l’administration sous-jacente familière. Chez Stackscale, nous déployons et exploitons Proxmox VE sur une &lt;a href=&quot;https://www.stackscale.fr/produits/&quot;&gt;infrastructure dédiée&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Licence de Proxmox VE&lt;/strong&gt; : GNU AGPLv3.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dernière version (septembre 2026)&lt;/strong&gt; : Proxmox VE 9.2, du 21 mai 2026.&lt;/p&gt;&lt;h2&gt;Liste des distributions Linux populaires&lt;/h2&gt;&lt;p&gt;Voici la liste des distributions Linux présentées, par ordre alphabétique :&lt;/p&gt;&lt;figure&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Distribution Linux&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Licence&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Dernière version (en septembre 2026)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AlmaLinux&lt;/td&gt;&lt;td&gt;GPLv2 et autres licences&lt;/td&gt;&lt;td&gt;AlmaLinux OS 10.2 (mai 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Alpine Linux&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Alpine Linux 3.24 (juin 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Amazon Linux&lt;/td&gt;&lt;td&gt;licence Amazon fondée sur l’open source&lt;/td&gt;&lt;td&gt;Amazon Linux 2023&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Arch Linux&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Rolling release&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Asahi Linux&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Fedora Asahi Remix 44 (avril 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BlackArch Linux&lt;/td&gt;&lt;td&gt;licences diverses&lt;/td&gt;&lt;td&gt;Rolling release&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CentOS Linux&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;Abandonnée — fin de vie 31/12/2021&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CentOS Stream&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;CentOS Stream 10 (décembre 2024)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Clear Linux&lt;/td&gt;&lt;td&gt;GPL et autres licences&lt;/td&gt;&lt;td&gt;Abandonnée — Intel, 18/07/2025&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CloudLinux&lt;/td&gt;&lt;td&gt;GPL et licences propriétaires&lt;/td&gt;&lt;td&gt;CloudLinux OS 10.2 (mai 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Debian&lt;/td&gt;&lt;td&gt;BSD, GPL et autres licences libres&lt;/td&gt;&lt;td&gt;Debian 13 « Trixie » (août 2025)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;elementary OS&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;elementary OS 8.1.1 « Circe » (février 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fedora&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Fedora Linux 44 (avril 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fedora CoreOS&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Fedora CoreOS 44 (flux continu)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flatcar Container Linux&lt;/td&gt;&lt;td&gt;Apache License 2.0&lt;/td&gt;&lt;td&gt;Flatcar 4593.2.5 (août 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Gentoo&lt;/td&gt;&lt;td&gt;logiciel libre&lt;/td&gt;&lt;td&gt;Rolling release&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Knoppix&lt;/td&gt;&lt;td&gt;licences de logiciel libre&lt;/td&gt;&lt;td&gt;Knoppix 9.2 (2021) — sans activité&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Linux Mint&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Linux Mint 22.3 « Zena » (janvier 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Lubuntu&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Lubuntu 26.04 LTS (avril 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mageia&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Mageia 10 (juin 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Manjaro&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Manjaro 26.1 (août 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Navy Linux&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;Sans activité — dernière 8.6 (2022)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NixOS&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;td&gt;NixOS 26.05 « Yarara » (mai 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;openSUSE&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;openSUSE Leap 16.0 (octobre 2025)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Oracle Linux&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Oracle Linux 10 (juin 2025)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Peppermint OS&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;Images datées (Debian 13 / Devuan 6)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Proxmox VE&lt;/td&gt;&lt;td&gt;GNU AGPLv3&lt;/td&gt;&lt;td&gt;Proxmox VE 9.2 (mai 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Red Hat Enterprise Linux&lt;/td&gt;&lt;td&gt;GPL&lt;/td&gt;&lt;td&gt;RHEL 10 (mai 2025)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rocky Linux&lt;/td&gt;&lt;td&gt;BSD et autres licences libres&lt;/td&gt;&lt;td&gt;Rocky Linux 10.2 (mai 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Scientific Linux&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;Abandonnée — fin de vie 30/06/2024&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Slackware&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;Slackware 15.0 (février 2022)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SUSE Liberty Linux&lt;/td&gt;&lt;td&gt;support commercial&lt;/td&gt;&lt;td&gt;Intégrée dans SUSE Multi-Linux Support&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SUSE Linux Enterprise&lt;/td&gt;&lt;td&gt;GNU GPL et licences propriétaires&lt;/td&gt;&lt;td&gt;SUSE Linux Enterprise Server 16 (novembre 2025)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SUSE Linux Micro&lt;/td&gt;&lt;td&gt;GNU GPL et autres licences&lt;/td&gt;&lt;td&gt;SUSE Linux Micro 6.2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Talos Linux&lt;/td&gt;&lt;td&gt;Mozilla Public License 2.0&lt;/td&gt;&lt;td&gt;Talos Linux 1.14 (septembre 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Tizen&lt;/td&gt;&lt;td&gt;GPLv2, LGPL, Apache 2.0, BSD et autres&lt;/td&gt;&lt;td&gt;Tizen 10.0 (2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ubuntu&lt;/td&gt;&lt;td&gt;GPL et autres licences&lt;/td&gt;&lt;td&gt;Ubuntu 26.04 LTS (avril 2026)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VzLinux&lt;/td&gt;&lt;td&gt;GNU GPL&lt;/td&gt;&lt;td&gt;Sans activité — dernière 8.5 (2021)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Zorin OS&lt;/td&gt;&lt;td&gt;logiciel libre&lt;/td&gt;&lt;td&gt;Zorin OS 18.1 (avril 2026)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img src=&quot;https://www.stackscale.fr/wp-content/uploads/2022/02/distributions-linux-fr-2026-stackscale.jpg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/figure&gt;&lt;p&gt;Sur la page suivante, vous pouvez consulter les &lt;a href=&quot;https://w3techs.com/technologies/history_details/os-linux/all/y&quot;&gt;statistiques des distributions Linux les plus utilisées au cours de la dernière décennie&lt;/a&gt;. Et pour vérifier au jour le jour les versions, les dates de publication et les fins de support de chaque système, le &lt;a href=&quot;https://linuxgratis.com/en&quot;&gt;répertoire Linux Gratis&lt;/a&gt; tient une fiche par distribution, pour plus de deux cents systèmes d’exploitation, mise à jour en continu.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>C&#39;est toujours une histoire de budget</title>
<link>https://ludovic.hirlimann.net/2025/10/cest-toujours-une-histoire-de-budget.html</link>
<guid isPermaLink="false">gTWYBggExS_bxGLxIgT5pd3ErfHqNoqSwpI46A==</guid>
<pubDate>Fri, 11 Sep 2026 18:29:01 +0000</pubDate>
<description>En 2010 ou en 2011, dans le cadre d&#39;une conférence organisé par l&#39;association Aristote j&#39;avais engagé la conversation avec un colonel de la Gendarmerie Nationale. À l&#39;époque, je travaillais pour Mozilla messaging et la gendarmerie utilisait Thunderbird, car celui-ci gérait les ACLs au niveau imap. Nous avions alors discuté du pourquoi du comment la gendarmerie était passée à Linux.</description>
<content:encoded>&lt;div&gt;&lt;a href=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Gendbuntu_22.04.jpg/500px-Gendbuntu_22.04.jpg&quot;&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Gendbuntu_22.04.jpg/500px-Gendbuntu_22.04.jpg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;

En 2010 ou en 2011, dans le cadre d&amp;#39;une conférence organisé par l&amp;#39;association Aristote j&amp;#39;avais engagé la conversation avec un colonel de la Gendarmerie Nationale. À l&amp;#39;époque, je travaillais pour Mozilla messaging et la gendarmerie utilisait Thunderbird, car celui-ci gérait les &lt;a href=&quot;https://fr.wikipedia.org/wiki/Access_Control_List&quot;&gt;ACL&lt;/a&gt;s au niveau imap. Nous avions alors discuté du pourquoi du comment la gendarmerie était passée à Linux.&lt;/p&gt;&lt;p&gt;On m&amp;#39;avait alors expliqué, que comme beaucoup d&amp;#39;entreprises, le pole informatique gérait aussi les télécommunications. Les communications pour la gendarmerie, c&amp;#39;est être capable d&amp;#39;envoyer des messages depuis une ile perdue du pacifique ou depuis le fin fond de la forêt tropicale guyanaise. Une très grosse partie du budget de ce service partait donc dans les équipements télécoms. La mise à niveau de l&amp;#39;OS de Microsoft ne rentrait pas dans le budget. Après &lt;a href=&quot;https://fr.wikipedia.org/wiki/Preuve_de_concept&quot;&gt;une maquette rapide&lt;/a&gt;, la décision avait été prise de :&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Déployer &lt;a href=&quot;https://fr.wikipedia.org/wiki/GendBuntu&quot;&gt;Genbuntu&lt;/a&gt; sur les machines de services&lt;/li&gt;&lt;li&gt;Mettre la distribution à disposition des gendarmes dans un cadre privé (pour utiliser la même chose à la maison qu&amp;#39;au travail) &lt;/li&gt;&lt;/ul&gt;</content:encoded>
</item>
<item>
<title>Desktop software I use June 2025 edition</title>
<link>https://ludovic.hirlimann.net/2025/06/destop-software-i-use-june-2025-edition.html</link>
<guid isPermaLink="false">pl8pdd7wOiN9sjsrve9k9PU_mRV-HiWrILFcCQ==</guid>
<pubDate>Fri, 11 Sep 2026 18:29:00 +0000</pubDate>
<description>I currently run Fedora 42 as my main work and private machine.</description>
<content:encoded>&lt;p&gt; I currently run Fedora 42 as my main work and private machine.&lt;/p&gt;&lt;p&gt;Desktop software: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Firefox for work because that&amp;#39;s the only viable alternative&lt;/li&gt;&lt;li&gt;Firefox nightly because testing releases is important and a very easy way to contribute&lt;/li&gt;&lt;li&gt;Thunderbird, so I can read four email accounts at the same time and get notifications&lt;/li&gt;&lt;li&gt;NewsFlash because I *need* an RSS feed reader.&lt;/li&gt;&lt;li&gt;Hexchat - because I still use IRC (three different networks) &lt;/li&gt;&lt;li&gt;Papers because I like the idea of a Rust based PDF viewer&lt;/li&gt;&lt;li&gt;Google chrome because I need to access teams meetings once in a while&lt;/li&gt;&lt;li&gt;Chromium so I can play TTRPG with foundryvtt&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Command line tools:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Podman I&amp;#39;m trying not to use docker to see if it&amp;#39;s viable on my new work machine&lt;/li&gt;&lt;li&gt; jq, awk, cat , less and normal unix tools.&lt;/li&gt;&lt;li&gt;lnav for log reading&lt;/li&gt;&lt;li&gt;atuin for shell history management&lt;/li&gt;&lt;li&gt;fish as my default shell &lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;</content:encoded>
</item>
<item>
<title>August 2026 ClangBuiltLinux Work | Nathan Chancellor</title>
<link>https://nathanchance.dev/posts/august-2026-cbl-work/</link>
<guid isPermaLink="false">hPwuy3kdXrkJJfQ0OA65pXk7eM2IrXcy9_wtWQ==</guid>
<pubDate>Fri, 11 Sep 2026 14:18:14 +0000</pubDate>
<description>Occasionally, I will forget to link something from the mailing list in this post. To see my full mailing list activity (patches, reviews, and reports), you can view it on lore.kernel.org. Linux kernel patches Build errors: These are patches to fix various build errors that I found through testing different configurations with LLVM or were exposed by our continuous integration setup. The kernel needs to build in order to be run :)</description>
<content:encoded>&lt;p&gt;Occasionally, I will forget to link something from the mailing list in this post. To see my full mailing list activity (patches, reviews, and reports), you can view it on &lt;a href=&quot;https://lore.kernel.org/all/?q=f:nathan@kernel.org&quot;&gt;lore.kernel.org&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Linux kernel patches#&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Build errors: These are patches to fix various build errors that I found through testing different configurations with LLVM or were exposed by our continuous integration setup. The kernel needs to build in order to be run :)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;thermal/drivers/qcom-spmi-mbg-tm: Add module namespace import for IIO_CONSUMER&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260812-qcom-spmi-mbg-tm-ns-modpost-error-v1-1-d849390d2714@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;net: macb: Move macb_{alloc,free}_tieoff() out of CONFIG_OF block&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260818-macb-fix-no-of-build-v1-1-f2a009616384@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Miscellaneous fixes and improvements: These are fixes and improvements that don’t fit into a particular category but matter in some way to my other work.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ARM: Fix get_cycles() after delay_read_timer() conversion&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260819-fix-arm-get_cycles-v1-1-208bf07ac540@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stable backports and fixes: It is important to make sure that the stable trees are as free from issues as possible, as those are the trees that devices and users use; for example, Android and Chrome OS regularly merge from stable, so if there is a problem that will impact those trees that we fixed in mainline, it should be backported.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260814025208.GA1929807@ax162/&quot;&gt;&lt;code&gt;Backports of c1f3e770eec26d6f96dd6d2ea30555ba7c09a244 for 6.6 and 6.1&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260814052439.430858-1-nathan@kernel.org/&quot;&gt;&lt;code&gt;[PATCH 6.12 0/2] Backport of 6ee149f61bcce39692f0335a01e99355d4cec8da&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Warning fixes: These are patches to fix various warnings that appear with LLVM. I used to go into detail about the different warnings and what they mean, but the important takeaway for this section is that the kernel should build warning free, as &lt;a href=&quot;https://lore.kernel.org/r/CAHk-=wifoM9VOp-55OZCRcO9MnqQ109UTuCiXeZ-eyX_JcNVGg@mail.gmail.com/&quot;&gt;all developers should be using &lt;code&gt;CONFIG_WERROR&lt;/code&gt;&lt;/a&gt;, which will turn these all into failures. Maybe these should be in the build failures section…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;swim3: Add missing MODULE_DESCRIPTION&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260811-swim3-module-description-v1-1-28398c5a0e32@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scsi: qla2xxx: Fix size_t format specifier in qla29xx_process_rd_image()&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260811-scsi-qla2xxxx-qla_init-wformat-v1-1-50760021914f@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arch_numa: Avoid false positive fortify warning in setup_node_to_cpumask_map()&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260811-arch_numa-avoid-fortify-warning-v1-1-59ce3e689f3a@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://lore.kernel.org/20260813-arch_numa-avoid-fortify-warning-v2-1-093ad97a78df@kernel.org/&quot;&gt;&lt;code&gt;v2&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scsi: ibmvfc: Fix use of uninitialized rport in ibmvfc_do_work()&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260817-ibmvscsi-rport-wuninitialized-v1-1-0fdfb27a5f01@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/sorttable: Mark long_size as __maybe_unused&lt;/code&gt; (&lt;a href=&quot;https://lore.kernel.org/20260831-sorttable-long_size-unused-but-set-global-v1-1-8a96b88697e5@kernel.org/&quot;&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Patch handling, review, and input#&lt;/h2&gt;&lt;p&gt;For the next sections, I link directly to my first response in the thread when possible but there are times where the link is to the main post. My responses can be seen inline by going to the bottom of the thread and clicking on my name.&lt;/p&gt;&lt;p&gt;Reviewing patches that are submitted is incredibly important, as it helps ensure good code quality due to catching mistakes before the patches get accepted and it can help get patches accepted faster, as some maintainers will blindly pick up patches that have been reviewed by someone that they trust.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260803161203.GA953175@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] riscv/runtime-const: Disable linker relaxation for RUNTIME_MAGIC&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260803174736.GA1067866@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] Documentation: warn users not to use select on choice options in Kconfig&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260803181217.GB1067866@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH 1/1] scripts: kstack_erase: use relative stackleak plugin path&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260803195135.GA1083357@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH 0/2] alpha: enable building with clang&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260804183042.GA300797@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] MAINTAINERS: add Julian Braha as Kconfig reviewer&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260807185259.GA941196@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] arm: mediatek: fix secondary CPU boot on Thumb-2 kernels with Clang&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260807190513.GA2638974@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v3] tee: remove TZMEM_MODE_GENERIC&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/178613777751.32781.14792177228607560956.b4-review@b4/&quot;&gt;&lt;code&gt;Re: [PATCH 0/2] modpost: error logging cleanups&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/178614091702.32781.13796520858880316981.b4-review@b4/&quot;&gt;&lt;code&gt;Re: [PATCH] kbuild: let the environment set HOSTPKG_CONFIG&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260811204327.GA1477601@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] Bluetooth: hci_sync: add conditional locking annotations&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260811223622.GA934543@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v2] soc: qcom: ubwc: Fix link error when QCOM_SMEM=n&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260813232350.GA312295@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v4 0/3] soc: qcom: ubwc: Fix link error&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260817181212.GA1249844@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH 2/2] kbuild: rust: keep Rust objects out of Clang LTO with inline helpers&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260817181743.GB1249844@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v6 0/4] soc: qcom: ubwc: Fix link error when QCOM_SMEM=n&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260817185146.GC1249844@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v2] kstack_erase: suppress -grecord-gcc-switches for external module builds&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/178707966024.2113250.6051873542503340409.b4-review@b4/&quot;&gt;&lt;code&gt;Re: [PATCH] scripts: Make the code use consistent syntax&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/178707985863.2113250.4007818694470388435.b4-review@b4/&quot;&gt;&lt;code&gt;Re: [PATCH] kconfig: error out for recursive range&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/178708267641.2113250.8208366109143651745.b4-review@b4/&quot;&gt;&lt;code&gt;Re: [PATCH 1/1] kbuild: record real-prereqs in .cmd files&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260819194039.GA3686901@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v3] ACPI: scan: Avoid registering platform devices with resource overlaps&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260821190701.GA3030879@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH] kbuild: ubsan: skip UBSAN for external modules by default&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260828175708.GA3403925@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH 12/27] kbuild: Defer running objtool to link time for all CFG features&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Issue triage, input, and reporting#&lt;/h2&gt;&lt;p&gt;The unfortunate thing about working at the intersection of two projects is we will often find bugs that are not strictly related to the project, which require some triage and reporting back to the original author of the breakage so that they can be fixed and not impact our own testing. Some of these bugs fall into that category while others are issues strictly related to this project.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ClangBuiltLinux/linux/issues/2170#issuecomment-5173130333&quot;&gt;&lt;code&gt;RISC-V kCFI boot hang after LLVM commit 434e4e15f6a3&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260804202217.GA1109939@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH V17 0/7] Rust Support for powerpc&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260807180245.GA4067747@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH 6.12 289/337] mm/slab: prevent unbounded recursion in free path with new kmalloc type&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260818165116.GA1335107@ax162/&quot;&gt;&lt;code&gt;Re: [REGRESSION] mainline/master: (build) in arch/arm/kernel/entry-common.o (/tmp/kci/linux/scripts/Makefile...&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260819003752.GA3063251@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v3] ACPI: scan: Avoid registering platform devices with resource overlaps&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260819184803.GA3333711@ax162/&quot;&gt;&lt;code&gt;Re: [GIT pull] timers/cleanups for v7.3-rc1&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260819235918.GA2021182@ax162/&quot;&gt;&lt;code&gt;Re: [PATCH v2] fbdev: platinumfb: add error checking for ioremap calls&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/llvm/llvm-project/issues/138272#issuecomment-540476747&quot;&gt;&lt;code&gt;Add builtin/intrinsic to get current instruction pointer?&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Tooling improvements#&lt;/h2&gt;&lt;p&gt;These are changes to various tools that we use, such as our continuous integration setup, booting utilities, toolchain building scripts, or other closely related projects such as &lt;a href=&quot;https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/&quot;&gt;AOSP’s distribution of LLVM&lt;/a&gt; and TuxMake.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ClangBuiltLinux/continuous-integration2/pull/938&quot;&gt;&lt;code&gt;Revert accidental LLVM_IAS=1 enablement for sparc64 with clang-22&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ClangBuiltLinux/tc-build/pull/348&quot;&gt;&lt;code&gt;build-llvm.py: Deduplicate &amp;#39;--targets&amp;#39;&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ClangBuiltLinux/tc-build/pull/349&quot;&gt;&lt;code&gt;build-binutils.py: Add support for sparc64&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kernelci/tuxmake/pull/303&quot;&gt;&lt;code&gt;Update clang-nightly to 24 and add clang-23&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ClangBuiltLinux/continuous-integration2/pull/940&quot;&gt;&lt;code&gt;Update stable anchor to 7.2&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Behind the scenes#&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Every day that there is a new &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/&quot;&gt;linux-next&lt;/a&gt; release, I rebase and build a few different kernel trees then boot and runtime test them on several different machines, including a SolidRun Honeycomb LX2, an Ampere Altra Developer Platform, four Intel-based devices, and two AMD-based devices. This is not always visible because I do not report anything unless there is something broken but it can take up to a few hours each day, depending on the amount of churn and issues uncovered.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I continue to upload prebuilt, fast versions of LLVM for kernel developers and our continuous integration to use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260812162742.GA101585@ax162/&quot;&gt;23.1.0-rc3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/20260827190431.GA1817346@ax162/&quot;&gt;23.1.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I developed &lt;a href=&quot;https://github.com/nathanchance/continuous-integration3&quot;&gt;a solid, working prototype for the third generation of ClangBuiltLinux continuous integration&lt;/a&gt; to permit moving to infrastructure that we have full authority over.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Special thanks#&lt;/h2&gt;&lt;p&gt;Special thanks to Google and the Linux Foundation for &lt;a href=&quot;https://www.linuxfoundation.org/press/press-release/google-funds-linux-kernel-developers-to-focus-exclusively-on-security&quot;&gt;sponsoring my work&lt;/a&gt;.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Un ingeniero de ARM optimiza la compilación de Linux a partir de código «horrible» generado por IA</title>
<link>https://www.muylinux.com/2026/09/09/compilacion-linux-ia-horrible/</link>
<guid isPermaLink="false">d6wNIrkoRjLgADCU-tCcfZZNwfi0T55P-UaIcA==</guid>
<pubDate>Fri, 11 Sep 2026 10:53:32 +0000</pubDate>
<description>La inteligencia artificial puede ayudar a mejorar Linux, aunque el código que genera deje bastante que desear. Es lo que cuenta Lorenzo Stoakes, ingeniero de ARM y veterano desarrollador del kernel, que ha presentado una serie de 23 parches para acelerar su compilación tras apoyarse en un modelo de lenguaje para localizar y resolver cuellos […] La entrada Un ingeniero de ARM optimiza la compilación de Linux a partir de código «horrible» generado por IA es original de MuyLinux</description>
<content:encoded>&lt;p&gt;&lt;img src=&quot;https://www.muylinux.com/wp-content/uploads/2026/09/ai.jpg&quot; alt=&quot;&quot; title=&quot;&quot;/&gt;&lt;/p&gt;&lt;p&gt;La &lt;a href=&quot;https://www.muylinux.com/tag/inteligencia-artificial/&quot;&gt;inteligencia artificial&lt;/a&gt; puede ayudar a mejorar Linux, aunque el código que genera deje bastante que desear. Es lo que cuenta Lorenzo Stoakes, ingeniero de ARM y veterano desarrollador del kernel, que ha presentado una serie de 23 parches para acelerar su compilación tras apoyarse en un modelo de lenguaje para localizar y resolver cuellos de botella.&lt;/p&gt;&lt;p&gt;Según recoge &lt;a href=&quot;https://www.phoronix.com/news/AI-To-Faster-Linux-Kernel-Comp&quot;&gt;Phoronix&lt;/a&gt;, el problema está en distintas fases del proceso de compilación que se ejecutan en un solo hilo y que terminan frenando el conjunto, por lo que el trabajo realizado por Stoakes se centra en &lt;strong&gt;paralelizar esas tareas y mejorar la eficiencia del proceso&lt;/strong&gt;, con resultados que, de acuerdo con las pruebas publicadas, pueden llegar a ser considerables.&lt;/p&gt;&lt;p&gt;En concreto, Stoakes señala una compilación &lt;strong&gt;alrededor de un 36 % más rápida con todos los módulos habilitados&lt;/strong&gt;, hasta un 70 % más rápida en compilaciones incrementales y hasta aproximadamente un 90 % en las denominadas «noop», aquellas en las que no hay cambios que compilar, aunque conviene aclarar que ese último porcentaje no describe lo que se tarda en construir el kernel desde cero.&lt;/p&gt;&lt;p&gt;Por lo demás, los cambios afectan a diferentes piezas de la infraestructura de compilación de Linux, entre ellas Kbuild, kallsyms, modpost, objtool y mksysmap, además del sistema de compilación de Rust. La propuesta abarca, por tanto, varios puntos del proceso, y las pruebas recogidas en la noticia muestran mejoras con distintas configuraciones del kernel y equipos.&lt;/p&gt;&lt;p&gt;Hasta aquí, lo que viene a ser una optimización técnica con cifras llamativas. Lo particular de este caso, sin embargo, es cómo se ha llegado a ese resultado y la franqueza con la que lo explica su autor: &lt;strong&gt;la IA generó mucho código, buena parte del cual califica de «horrible»&lt;/strong&gt;. Stoakes no especifica qué modelo utilizó, pero sí detalla que lo empleó primero para localizar los cuellos de botella y después para buscar cómo corregirlos.&lt;/p&gt;&lt;p&gt;La IA hizo más que «simplemente» escribir código, ya que también coordinó compilaciones, pruebas, depuración y análisis. Vamos, que le faltó ponerse el &lt;em&gt;prompt&lt;/em&gt; a sí misma. Por su parte, el desarrollador asegura haber auditado extensamente y reescrito buena parte del resultado y haber revisado en profundidad los mensajes de los &lt;em&gt;commits&lt;/em&gt;, la presentación de la propuesta y los comentarios del código.&lt;/p&gt;&lt;p&gt;Pero la intervención humana va un poco más allá y Stoakes afirma haber comprobado manualmente tanto la compilación como el funcionamiento de los kernels generados con estos cambios, así como haber verificado las mejoras de rendimiento. Además, para dejar constancia del uso de IA, &lt;strong&gt;todos los commits incluyen una etiqueta «Assisted-by»&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;¿Y ahora? La &lt;a href=&quot;https://lore.kernel.org/rust-for-linux/20260908-build-speedup-v1-0-5dc1ac01672d@kernel.org/&quot;&gt;serie de parches&lt;/a&gt; se ha presentado para revisión, por lo que todavía habrá que ver qué termina incorporándose al kernel. De momento, el caso deja un ejemplo interesante del uso de estas herramientas en su desarrollo, con resultados prometedores y un trabajo de revisión y corrección humana que el propio autor se ha encargado de subrayar. Un capítulo más en la historia de la IA en Linux.&lt;/p&gt;&lt;p&gt;La entrada &lt;a href=&quot;https://www.muylinux.com/2026/09/09/compilacion-linux-ia-horrible/&quot;&gt;Un ingeniero de ARM optimiza la compilación de Linux a partir de código «horrible» generado por IA&lt;/a&gt; es original de MuyLinux&lt;/p&gt;</content:encoded>
</item>
</channel>
</rss>
