<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Artificial truth</title><link href="https://dustri.org/b/" rel="alternate"></link><link href="https://dustri.org/b/atom.xml" rel="self"></link><id>https://dustri.org/b/</id><updated>2026-04-21T02:00:00+02:00</updated><entry><title>swic: a simple web interface for calibre</title><link href="https://dustri.org/b/swic-a-simple-web-interface-for-calibre.html" rel="alternate"></link><published>2026-04-21T02:00:00+02:00</published><updated>2026-04-21T02:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-04-21:/b/swic-a-simple-web-interface-for-calibre.html</id><summary type="html">&lt;p&gt;I'm ~regularly doing lightweight security audits of the services I'm running
exposed on the internet. One of them is &lt;a href="https://github.com/janeczku/calibre-web"&gt;calibre-web&lt;/a&gt;.
After 2h and &lt;a href="https://github.com/janeczku/calibre-web/issues?q=is%3Apr%20author%3Ajvoisin%20created%3A%3E2025"&gt;17 security-related
pull-requests&lt;/a&gt;
later, I gave up and decided to write a replacement:
&lt;a href="https://github.com/jvoisin/swic"&gt;swic&lt;/a&gt;. It only has 3 user-facing
features: showing the ebooks as a list, a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm ~regularly doing lightweight security audits of the services I'm running
exposed on the internet. One of them is &lt;a href="https://github.com/janeczku/calibre-web"&gt;calibre-web&lt;/a&gt;.
After 2h and &lt;a href="https://github.com/janeczku/calibre-web/issues?q=is%3Apr%20author%3Ajvoisin%20created%3A%3E2025"&gt;17 security-related
pull-requests&lt;/a&gt;
later, I gave up and decided to write a replacement:
&lt;a href="https://github.com/jvoisin/swic"&gt;swic&lt;/a&gt;. It only has 3 user-facing
features: showing the ebooks as a list, a searchsbar, and allowing the user to
download the ebooks. I don't need anything else. UI-wise, it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dustri.org/b/images/swic.png"&gt;&lt;img alt="screenshot of the interface" src="https://dustri.org/b/images/swic.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's written in go, meaning that it's both trivial to deploy and to audit. It
has a single direct dependency
(&lt;a href="https://modernc.org/sqlite"&gt;&lt;code&gt;modernc.org/sqlite&lt;/code&gt;&lt;/a&gt;) to read calibre's database.
It doesn't handle users, doesn't need to have write-access to anything, doesn't
process untrusted data besides user-provided urls, makes use of Go's
&lt;a href="https://go.dev/blog/osroot"&gt;&lt;code&gt;os.root&lt;/code&gt;&lt;/a&gt; to prevent path traversals. The
interface is fully responsive and doesn't use any javascript.&lt;/p&gt;
&lt;p&gt;The code isn't the prettiest, but the whole thing was written in an evening.
You should replace calibre-web with it before somebody drops an RCE :p&lt;/p&gt;</content><category term="dev"></category></entry><entry><title>A quick look at __pledge_open(2)</title><link href="https://dustri.org/b/a-quick-look-at-__pledge_open2.html" rel="alternate"></link><published>2026-04-02T14:30:00+02:00</published><updated>2026-04-02T14:30:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-04-02:/b/a-quick-look-at-__pledge_open2.html</id><summary type="html">&lt;p&gt;A recent article of the OpenBSD journal caught me attention: &lt;a href="https://undeadly.org/cgi?action=article;sid=20260320085305"&gt;Pledge changes in
7.9-beta&lt;/a&gt;
(&lt;a href="https://web.archive.org/web/20260320154656/https://undeadly.org/cgi?action=article;sid=20260320085305"&gt;archive.org mirror&lt;/a&gt; as it's currently offline).&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://marc.info/?l=openbsd-ports&amp;amp;m=177389567528083&amp;amp;w=2"&gt;quoted message&lt;/a&gt;
starts with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Previously under certain promises it was possible to open certain files
or devices even if the program didn't pledge "rpath" or "wpath". This …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;A recent article of the OpenBSD journal caught me attention: &lt;a href="https://undeadly.org/cgi?action=article;sid=20260320085305"&gt;Pledge changes in
7.9-beta&lt;/a&gt;
(&lt;a href="https://web.archive.org/web/20260320154656/https://undeadly.org/cgi?action=article;sid=20260320085305"&gt;archive.org mirror&lt;/a&gt; as it's currently offline).&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://marc.info/?l=openbsd-ports&amp;amp;m=177389567528083&amp;amp;w=2"&gt;quoted message&lt;/a&gt;
starts with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Previously under certain promises it was possible to open certain files
or devices even if the program didn't pledge "rpath" or "wpath". This behavior
has gone away in 7.9-beta; libc uses the special &lt;code&gt;__pledge_open(2)&lt;/code&gt; syscall which
cannot be used outside of libc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So a new syscall, bypassing &lt;code&gt;pledge/unveil&lt;/code&gt;, interesting. The "cannot be used
outside of libc" is likely referring to
&lt;a href="https://isopenbsdsecu.re/mitigations/pinsyscall/"&gt;pinsyscall&lt;/a&gt;, which is an
indirect call away. Let's check if this is indeed a sandbox escape. The
function
&lt;a href="https://github.com/openbsd/src/blob/4245707926efbf4b027899ae0328f0c436ca7e10/lib/libc/net/getservent.c#L47"&gt;&lt;code&gt;setservent_r&lt;/code&gt;&lt;/a&gt;
has a call to &lt;code&gt;__pledge_open&lt;/code&gt;, so let's jump directly on the &lt;code&gt;call&lt;/code&gt; to please
pinsyscall:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;sys/ptrace.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;#define F &amp;quot;/tmp/pwned.txt&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;unrestricted_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;on_sigtrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;siginfo_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Catch the int3 of setprotoent&amp;#39;s epilogue function&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;STDERR_FILENO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;caught SIGTRAP&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Trying to read fd: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;can&amp;#39;t read&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unveil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unveil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;sigaction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sa_sigaction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on_sigtrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sa_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SA_SIGINFO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sigemptyset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sa_mask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sigaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIGTRAP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sigaction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got fd for open: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// offsets for -current valid at 2026-04-02&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daemon_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// get the address of the call to __pledge_open in setprotoent&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unrestricted_open_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daemon_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x00076980&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x000E0A07&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unrestricted_open&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unrestricted_open_fcn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unrestricted_open&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;unrestricted_open_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unrestricted_open_fcn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;openbsd$ clang ./test.c  &amp;amp;&amp;amp; ./a.out&lt;/span&gt;
&lt;span class="go"&gt;1 warning generated.&lt;/span&gt;
&lt;span class="go"&gt;Got fd for open: -1&lt;/span&gt;
&lt;span class="go"&gt;caught SIGTRAP&lt;/span&gt;
&lt;span class="go"&gt;Trying to read fd: 4&lt;/span&gt;
&lt;span class="go"&gt;can&amp;#39;t read&lt;/span&gt;
&lt;span class="go"&gt;openbsd$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because there is a check in the form of
&lt;a href="https://github.com/openbsd/src/blob/4245707926efbf4b027899ae0328f0c436ca7e10/sys/kern/kern_pledge.c#L645"&gt;&lt;code&gt;pledge_namei&lt;/code&gt;&lt;/a&gt;, with hardcoded paths:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt; * Need to make it more obvious that one cannot get through here&lt;/span&gt;
&lt;span class="cm"&gt; * without the right flags set&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="nf"&gt;pledge_namei&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;proc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;nameidata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// […]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;     * In specific promise situations, __pledge_open() can open&lt;/span&gt;
&lt;span class="cm"&gt;     * specific paths and ignores rpath, wpath, or unveil restrictions.&lt;/span&gt;
&lt;span class="cm"&gt;     */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_unveil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UNVEIL_PLEDGEOPEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef SMALL_KERNEL&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* To save ramdisk space, we trust the libc provided paths */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;checkpledgepaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;strncmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/usr/share/zoneinfo/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/usr/share/zoneinfo/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGEPATH_ZONEINFO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/usr/share/zoneinfo/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="cm"&gt;/* bad path */&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* Invalid path provided to __pledge_open */&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pledge_fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EACCES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ple&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;quot;stdio&amp;quot; - for daemon(3) or other such functions */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_NULL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_WPATH&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;quot;tty&amp;quot; - readpassphrase(3), getpass(3) */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_TTY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_TTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_WPATH&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;quot;getpw&amp;quot; requirements */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_SPWD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* XXX should remove nip check! */&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_GETPW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EPERM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_PWD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_GROUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_NETID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_GETPW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;quot;dns&amp;quot; requirements */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_RESOLVCONF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_HOSTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_SERVICES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_PROTOCOLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_DNS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* tzset() often happen late in programs */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_LOCALTIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="cm"&gt;/* FALLTHROUGH */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;PLEDGEPATH_ZONEINFO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PLEDGE_RPATH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ni_cnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cn_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYPASSUNVEIL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pledgepaths table is broken&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif &lt;/span&gt;&lt;span class="cm"&gt;/* SMALL_KERNEL */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// […]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Maybe it's worth reading emails in their entirety after all, instead of only
the first paragraph, as it ended with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The list of promises and the special paths which could previously be
opened under that promise is:&lt;/p&gt;
&lt;p&gt;stdio
  /dev/null (rpath or wpath)
  /etc/localtime
  /usr/share/zoneinfo&lt;/p&gt;
&lt;p&gt;tty
  /dev/tty (rpath or wpath)&lt;/p&gt;
&lt;p&gt;dns
  /etc/resolv.conf
  /etc/hosts
  /etc/services
  /etc/protocols&lt;/p&gt;
&lt;p&gt;getpw
  /etc/group
  /etc/netid
  /etc/pwd.db (the .db files really should be left to the system)
  /etc/spwd.db (could not open, but returned EPERM)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a small consolation, it might still be a valid bypass on OpenBSD with a
compiled with &lt;code&gt;SMALL_KERNEL&lt;/code&gt;, but OpenBSD being what it is, &lt;code&gt;-current&lt;/code&gt; doesn't
compile with the &lt;code&gt;SMALL_KERNEL&lt;/code&gt; option, and I can't be arsed to fix it:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;openbsd# make&lt;/span&gt;
&lt;span class="go"&gt;cc -g -Werror -Wall -Wimplicit-function-declaration  -Wno-pointer-sign  -Wframe-larger-than=2047 -Wno-address-of-packed-member -Wno-constant-conversion  -Wno-unused-but-set-variable -Wno-gnu-folding-constant -mcmodel=kernel -mno-red-zone -mno-sse2 -mno-sse -mno-3dnow  -mno-mmx -msoft-float -fno-omit-frame-pointer -ffreestanding -fno-pie -msave-args -mno-retpoline -fcf-protection=none -Oz  -pipe -nostdinc -I/sys -I/usr/src/sys/arch/amd64/compile/GENERIC/obj -I/sys/arch  -I/sys/dev/pci/drm/include  -I/sys/dev/pci/drm/include/uapi  -I/sys/dev/pci/drm/amd/include/asic_reg  -I/sys/dev/pci/drm/amd/include  -I/sys/dev/pci/drm/amd/amdgpu  -I/sys/dev/pci/drm/amd/display  -I/sys/dev/pci/drm/amd/display/include  -I/sys/dev/pci/drm/amd/display/dc  -I/sys/dev/pci/drm/amd/display/amdgpu_dm  -I/sys/dev/pci/drm/amd/pm/inc  -I/sys/dev/pci/drm/amd/pm/legacy-dpm  -I/sys/dev/pci/drm/amd/pm/swsmu  -I/sys/dev/pci/drm/amd/pm/swsmu/inc  -I/sys/dev/pci/drm/amd/pm/swsmu/smu11  -I/sys/dev/pci/drm/amd/pm/swsmu/smu12  -I/sys/dev/pci/drm/amd/pm/swsmu/smu13  -I/sys/dev/pci/drm/amd/pm/swsmu/smu14  -I/sys/dev/pci/drm/amd/pm/powerplay/inc  -I/sys/dev/pci/drm/amd/pm/powerplay/hwmgr  -I/sys/dev/pci/drm/amd/pm/powerplay/smumgr  -I/sys/dev/pci/drm/amd/pm/swsmu/inc  -I/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if  -I/sys/dev/pci/drm/amd/display/dc/inc  -I/sys/dev/pci/drm/amd/display/dc/inc/hw  -I/sys/dev/pci/drm/amd/display/dc/clk_mgr  -I/sys/dev/pci/drm/amd/display/dc/dccg  -I/sys/dev/pci/drm/amd/display/dc/dio  -I/sys/dev/pci/drm/amd/display/dc/dpp  -I/sys/dev/pci/drm/amd/display/dc/dsc  -I/sys/dev/pci/drm/amd/display/dc/dwb  -I/sys/dev/pci/drm/amd/display/dc/hubbub  -I/sys/dev/pci/drm/amd/display/dc/hpo  -I/sys/dev/pci/drm/amd/display/dc/hwss  -I/sys/dev/pci/drm/amd/display/dc/hubp  -I/sys/dev/pci/drm/amd/display/dc/dml2  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/inc  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_core  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_mcg  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_pmo  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_standalone_libraries  -I/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/inc  -I/sys/dev/pci/drm/amd/display/dc/mmhubbub  -I/sys/dev/pci/drm/amd/display/dc/mpc  -I/sys/dev/pci/drm/amd/display/dc/opp  -I/sys/dev/pci/drm/amd/display/dc/optc  -I/sys/dev/pci/drm/amd/display/dc/pg  -I/sys/dev/pci/drm/amd/display/dc/resource  -I/sys/dev/pci/drm/amd/display/modules/inc  -I/sys/dev/pci/drm/amd/display/modules/hdcp  -I/sys/dev/pci/drm/amd/display/dmub/inc  -I/sys/dev/pci/drm/i915 -DDDB -DDIAGNOSTIC -DKTRACE -DACCOUNTING -DKMEMSTATS -DPTRACE -DPOOL_DEBUG -DCRYPTO -DSYSVMSG -DSYSVSEM -DSYSVSHM -DUVM_SWAP_ENCRYPT -DFFS -DFFS2 -DUFS_DIRHASH -DQUOTA -DEXT2FS -DMFS -DNFSCLIENT -DNFSSERVER -DCD9660 -DUDF -DMSDOSFS -DFIFO -DFUSE -DSOCKET_SPLICE -DTCP_ECN -DTCP_SIGNATURE -DINET6 -DIPSEC -DPPP_BSDCOMP -DPPP_DEFLATE -DPIPEX -DMROUTING -DMPLS -DBOOT_CONFIG -DUSER_PCICONF -DAPERTURE -DMTRR -DNTFS -DSUSPEND -DHIBERNATE -DSMALL_KERNEL -DPCIVERBOSE -DUSBVERBOSE -DWSDISPLAY_COMPAT_USL -DWSDISPLAY_COMPAT_RAWKBD -DWSDISPLAY_DEFAULTSCREENS=&amp;quot;6&amp;quot; -DX86EMU -DI915 -DONEWIREVERBOSE -DMAXUSERS=80 -D_KERNEL -MD -MP  -c /sys/dev/acpi/acpibtn.c&lt;/span&gt;
&lt;span class="go"&gt;/sys/dev/acpi/acpibtn.c:292:12: error: use of undeclared identifier &amp;#39;pwr_action&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;  292 |                         switch (pwr_action) {&lt;/span&gt;
&lt;span class="go"&gt;      |                                 ^&lt;/span&gt;
&lt;span class="go"&gt;1 error generated.&lt;/span&gt;
&lt;span class="go"&gt;*** Error 1 in /usr/src/sys/arch/amd64/compile/GENERIC (Makefile:2680 &amp;#39;acpibtn.o&amp;#39;)&lt;/span&gt;
&lt;span class="go"&gt;openbsd#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So who knows.&lt;/p&gt;
&lt;p&gt;(Thanks to K3 for looking into this we me.)&lt;/p&gt;</content><category term="security"></category></entry><entry><title>Quick notes on KERNSEAL</title><link href="https://dustri.org/b/quick-notes-on-kernseal.html" rel="alternate"></link><published>2026-03-25T15:30:00+01:00</published><updated>2026-03-25T15:30:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-03-25:/b/quick-notes-on-kernseal.html</id><summary type="html">&lt;p&gt;The mysterious unreadable &lt;code&gt;kernseal.txt&lt;/code&gt; file on &lt;a href="https://pax.grsecurity.net/docs/index.html"&gt;PaX' documentation
page&lt;/a&gt; has been sitting there since
2003, described as "sealed kernel storage design &amp;amp; implementation." In 2006, it
was &lt;a href="https://forums.grsecurity.net/viewtopic.php?f=1&amp;amp;t=1733#p6920"&gt;described
as&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the problem KERNSEAL sets out to solve is kernel self-protection, that is,
assuming arbitrary read/write access to kernel memory (by …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;The mysterious unreadable &lt;code&gt;kernseal.txt&lt;/code&gt; file on &lt;a href="https://pax.grsecurity.net/docs/index.html"&gt;PaX' documentation
page&lt;/a&gt; has been sitting there since
2003, described as "sealed kernel storage design &amp;amp; implementation." In 2006, it
was &lt;a href="https://forums.grsecurity.net/viewtopic.php?f=1&amp;amp;t=1733#p6920"&gt;described
as&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the problem KERNSEAL sets out to solve is kernel self-protection, that is,
assuming arbitrary read/write access to kernel memory (by some bug, but for all
i care, it could even be a mode 777 /dev/mem as well), the goal is to prevent
privilege elevation (vs. privilege abuse which is an even harder problem to
solve).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After many years of &lt;code&gt;KERNSEAL ETA WEN&lt;/code&gt; jokes on &lt;code&gt;#grsecurity&lt;/code&gt;, it was finally
made available to &lt;a href="https://grsecurity.net"&gt;grsecurity&lt;/a&gt; beta customers &lt;a href="https://twitter.com/grsecurity/status/1692643521025499474"&gt;in August
2023&lt;/a&gt; and 
to LTS ones &lt;a href="https://twitter.com/grsecurity/status/1745264708867772545"&gt;in January
2024&lt;/a&gt;. I was eagerly
expecting &lt;a href="https://infosec.exchange/@minipli"&gt;minipli&lt;/a&gt;'s blogpost on the topic,
but since none got published so far, I endeavoured to read an old patch a
friend of mine was kind enough to sling my way, and take/publish some
high-level notes while waiting for it, as
&lt;a href="https://twitter.com/grsecurity/status/1651743064480796673"&gt;apparently&lt;/a&gt; the
diff for &lt;code&gt;pax-linux-6.2.13-test6-kernseal-only.patch&lt;/code&gt; is "only" &lt;code&gt;66 files
changed, 1118 insertions(+), 361 deletions(-)&lt;/code&gt;. Odds are that most of my
understanding is completely wrong nonetheless, so take everything written here
with a mountain of salt. Also, I took an old patch and left some bits out out
of courtesy, as grsecurity isn't freely available anymore.&lt;/p&gt;
&lt;p&gt;The main idea behind &lt;code&gt;PAX_KERNSEAL&lt;/code&gt; seems to be the &lt;em&gt;constification&lt;/em&gt; of
dynamically allocated objects, a bit like
&lt;a href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options#Automatically_constify_eligible_structures"&gt;&lt;code&gt;PAX_CONSTIFY_PLUGIN&lt;/code&gt;&lt;/a&gt;
is doing for static ones, as well as completely hiding some of them as well.
It depends on a couple of things to enforce its
security invariants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PaX' &lt;a href="https://pax.grsecurity.net/docs/PaXTeam-H2HC15-RAP-RIP-ROP.pdf"&gt;RAP&lt;/a&gt;,
  to prevent existing code out-of-(intended)-order execution, otherwise an
  attacker could simply ROP their way around KERNSEAL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PAX_PRIVATE_KSTACKS&lt;/code&gt;, to defend against kthreads manipulating each other
  return addresses after RAP checks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONFIG_PAX_PER_CPU_PGD&lt;/code&gt;, to prevent other kthreads from accessing
  temporarily unsealed pages on a given CPU.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONFIG_PAGE_TABLE_ISOLATION&lt;/code&gt;, of course.&lt;/li&gt;
&lt;li&gt;Not having hibernation nor &lt;a href="https://en.wikipedia.org/wiki/Kexec"&gt;kexec&lt;/a&gt; support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It introduces two new page states via 
&lt;a href="https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html"&gt;GFP&lt;/a&gt;
flags, and stores those properties in the &lt;code&gt;struct page&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;__GFP_SEALED&lt;/code&gt;/&lt;code&gt;PG_sealed&lt;/code&gt;: The page is mapped &lt;strong&gt;read-only&lt;/strong&gt; in the direct
   map (the linear mapping of all physical memory.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__GFP_HIDDEN&lt;/code&gt;/&lt;code&gt;PG_hidden&lt;/code&gt;: The page is mapped &lt;strong&gt;invalid&lt;/strong&gt; (completely
   unmapped) in the direct map, so contents can't be read or written through
   the normal direct-map address.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;New corresponding migrate types (&lt;code&gt;MIGRATE_SEALED&lt;/code&gt; and &lt;code&gt;MIGRATE_HIDDEN&lt;/code&gt;) are
added to the buddy allocator, ensuring that sealed and hidden pages are grouped
together in dedicated pageblocks. Of course those types are non-mergeable,
preventing the allocator from stealing sealed/hidden blocks for normal
allocations.&lt;/p&gt;
&lt;p&gt;When a pageblock is set up for sealed or hidden use, &lt;code&gt;pax_setup_pageblock()&lt;/code&gt;
walks the PMD entries in the direct map and applies
&lt;code&gt;pmd_wrprotect()&lt;/code&gt; (for sealed) or &lt;code&gt;pmd_mkinvalid()&lt;/code&gt; (for hidden), followed by a
TLB flush. After allocation, &lt;code&gt;post_alloc_hook()&lt;/code&gt; verifies that page flags match
the requested GFP flags (sealed pages must have &lt;code&gt;PG_sealed&lt;/code&gt;, etc.), and updates
per-node statistics (&lt;code&gt;NR_SEALED&lt;/code&gt;, &lt;code&gt;NR_HIDDEN&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;As hidden pages have no valid direct-map mapping, the kernel needs a way to
temporarily access them, which is done via &lt;code&gt;pax_expose_page&lt;/code&gt;/&lt;code&gt;pax_hide_page&lt;/code&gt;
pair, a bit like
&lt;a href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options#Enforce_non-executable_kernel_pages"&gt;&lt;code&gt;KERNEXEC&lt;/code&gt;&lt;/a&gt;'s
&lt;code&gt;pax_open_kernel&lt;/code&gt;/&lt;code&gt;pax_close_kernel&lt;/code&gt; are doing to keep the kernel code
read-only.&lt;/p&gt;
&lt;p&gt;A dedicated &lt;code&gt;KM_USER_SLOT&lt;/code&gt; is reserved for KERNSEAL kmap operations, and every
&lt;code&gt;kmap&lt;/code&gt;-related call is hooked: if the page is hidden, it goes through
&lt;code&gt;pax_expose_page()&lt;/code&gt; to create a temporary per-CPU mapping; if sealed, access is
blocked entirely with &lt;code&gt;VM_BUG_ON_PAGE_ALWAYS&lt;/code&gt;, dumping the page and calling
&lt;code&gt;BUG()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A new kmalloc cache type (&lt;code&gt;KMALLOC_SEALED&lt;/code&gt;) is added, to allow the kernel to
allocated sealed data on a lower granularity than page-level. Temporarily
unseal capability (for initialization for example) is provided by
&lt;code&gt;pax_open_seal()&lt;/code&gt;/&lt;code&gt;pax_close_seal()&lt;/code&gt;, which are simply wrappers around
&lt;code&gt;pax_open_kernel&lt;/code&gt; and &lt;code&gt;pax_close_kernel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The most obvious usage of &lt;code&gt;KERNSEAL&lt;/code&gt; on the patch I have is on &lt;code&gt;struct cred&lt;/code&gt;:
The mutable fields (&lt;code&gt;usage&lt;/code&gt;, &lt;code&gt;rcu&lt;/code&gt;, &lt;code&gt;non_rcu&lt;/code&gt;) are split into a separate
&lt;code&gt;struct cred_rw&lt;/code&gt;, while the &lt;code&gt;cred&lt;/code&gt; structure itself is marked
&lt;code&gt;__mutable_const&lt;/code&gt;, with the &lt;code&gt;rw&lt;/code&gt; portion being actually a pointer to
separately-allocated mutable memory:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;*/
&lt;span class="w"&gt; &lt;/span&gt;struct cred {                                                                       
&lt;span class="gd"&gt;-       atomic_long_t   usage;&lt;/span&gt;
&lt;span class="gi"&gt;+       struct cred_rw {&lt;/span&gt;
&lt;span class="gi"&gt;+               /* RCU deletion */&lt;/span&gt;
&lt;span class="gi"&gt;+               union {&lt;/span&gt;
&lt;span class="gi"&gt;+                       int non_rcu;            /* Can we skip RCU deletion? */&lt;/span&gt;
&lt;span class="gi"&gt;+                       struct rcu_head rcu;    /* RCU deletion hook */&lt;/span&gt;
&lt;span class="gi"&gt;+               };&lt;/span&gt;
&lt;span class="gi"&gt;+#ifdef CONFIG_PAX_KERNSEAL      &lt;/span&gt;
&lt;span class="gi"&gt;+               struct cred     *cred;&lt;/span&gt;
&lt;span class="gi"&gt;+#endif&lt;/span&gt;
&lt;span class="gi"&gt;+               atomic_long_t   usage;   &lt;/span&gt;
&lt;span class="gi"&gt;+       }&lt;/span&gt;
&lt;span class="gi"&gt;+#ifdef CONFIG_PAX_KERNSEAL&lt;/span&gt;
&lt;span class="gi"&gt;+       *rw;&lt;/span&gt;
&lt;span class="gi"&gt;+#else&lt;/span&gt;
&lt;span class="gi"&gt;+       _rw;&lt;/span&gt;
&lt;span class="gi"&gt;+#endif&lt;/span&gt;

// [...]

&lt;span class="gi"&gt;+#ifdef CONFIG_PAX_KERNSEAL&lt;/span&gt;
&lt;span class="gi"&gt;+} __randomize_layout __mutable_const;&lt;/span&gt;
&lt;span class="gi"&gt;+#else&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;} __randomize_layout;
&lt;span class="gi"&gt;+#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and used like this:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gi"&gt;+#ifdef CONFIG_PAX_KERNSEAL&lt;/span&gt;
&lt;span class="gi"&gt;+#define to_cred_rw(cred)       (cred-&amp;gt;rw)&lt;/span&gt;
&lt;span class="gi"&gt;+#define to_cred(cred_rw)       (cred_rw-&amp;gt;cred)                          &lt;/span&gt;
&lt;span class="gi"&gt;+#else&lt;/span&gt;
&lt;span class="gi"&gt;+#define to_cred_rw(cred)       (&amp;amp;cred-&amp;gt;_rw)&lt;/span&gt;
&lt;span class="gi"&gt;+#define to_cred(cred_rw)       (container_of(cred_rw, struct cred, _rw))&lt;/span&gt;
&lt;span class="gi"&gt;+#endif&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means the credential's security-sensitive fields (UIDs, GIDs,
capabilities) live on sealed pages and cannot be tampered with, while the
reference count and RCU linkage live on normal writable memory.&lt;/p&gt;
&lt;p&gt;Debugging-wise, When a page fault occurs on a direct-mapped address, the fault
handler checks whether the page is sealed or hidden and provides a clear
diagnostic:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gi"&gt;+   if (is_direct_mapped_addr((void *)address)) {&lt;/span&gt;
&lt;span class="gi"&gt;+       struct page *page = virt_to_page((void *)address);&lt;/span&gt;
&lt;span class="gi"&gt;+       if (PageSealed(page) || PageHidden(page)) {&lt;/span&gt;
&lt;span class="gi"&gt;+           pr_alert(&amp;quot;BUG: unable to handle page fault for %s page at %pS\n&amp;quot;,&lt;/span&gt;
&lt;span class="gi"&gt;+               PageSealed(page) ? &amp;quot;sealed&amp;quot; : &amp;quot;hidden&amp;quot;, (void *)address);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Moreover, sealed and hidden page counts are exposed via &lt;code&gt;/proc/meminfo&lt;/code&gt; and
per-node &lt;code&gt;meminfo&lt;/code&gt;, plus per-process stats in &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/smaps&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Sealed:&lt;/code&gt; — total sealed pages in kB&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Hidden:&lt;/code&gt; — total hidden pages in kB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;New &lt;code&gt;kpageflags&lt;/code&gt; bits (&lt;code&gt;KPF_SEALED&lt;/code&gt; = 62, &lt;code&gt;KPF_HIDDEN&lt;/code&gt; = 63) are also exported.&lt;/p&gt;
&lt;p&gt;As for &lt;code&gt;PAX_PRIVATE_KSTACKS&lt;/code&gt; (in the context of &lt;code&gt;PAX_KERNSEAL&lt;/code&gt;), it creates a
per-CPU page table where each task gets a dedicated slot with guard pages. Only
the current task's stack is accessible, via dynamic PTE-level (un)mapping
magic. Underlying physical pages are allocated with &lt;code&gt;__GFP_HIDDEN&lt;/code&gt; of course.
For stack variables that require DMA/async access, an ad-hoc GCC plugin
identifies them and stores them in a per-task dedicated page.&lt;/p&gt;
&lt;p&gt;Even though &lt;code&gt;PAX_PRIVATE_KSTACKS&lt;/code&gt; and &lt;code&gt;PAX_KERNSEAL&lt;/code&gt; are conceptually simple
mitigation, they are likely super-tedious to apply to the Linux kernel code
behemoth. Tackling data-only attacks is hard, and the only other people
seriously trying to address them is Apple, with their hardware-based
KTRR/CTRR/GXF/APRR/PPL/SPTM/TXM mitigations. This makes KERNSEAL all the more
remarkable, as like everything produced by the PaX Team, it doesn't require
special hardware support. &lt;/p&gt;
&lt;p&gt;Another interesting property of KERNSEAL is that it can serve as a basis for
other interesting things, like ensuring that &lt;a href="https://x.com/grsecurity/status/1681338447695339520"&gt;no guest pages are available at
the hypervisor level in
KVM&lt;/a&gt; for example. I can't
wait to see what will be built on top next.&lt;/p&gt;
&lt;p&gt;All in all, unsurprisingly, KERNSEAL is yet another all-around tour de force
from the PaX Team, who keeps consistently producing stellar software-only
mitigations before everyone else, since almost 25 years.&lt;/p&gt;</content><category term="security"></category></entry><entry><title>Fixing Steam's "Download failed: http error 0" on Asahi Linux</title><link href="https://dustri.org/b/fixing-steams-download-failed-http-error-0-on-asahi-linux.html" rel="alternate"></link><published>2026-03-18T00:45:00+01:00</published><updated>2026-03-18T00:45:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-03-18:/b/fixing-steams-download-failed-http-error-0-on-asahi-linux.html</id><summary type="html">&lt;p&gt;Thanks to the &lt;a href="https://asahilinux.org/2024/10/aaa-gaming-on-asahi-linux/"&gt;amazing
work&lt;/a&gt; of the &lt;a href="https://asahilinux.org/community/"&gt;Asahi
Team&lt;/a&gt;, &lt;a href="https://steampowered.com"&gt;Steam&lt;/a&gt; is
running on my arm64 Linux on my Apple M2. Unfortunately, it seems that a recent
update broke the ability for Steam to speak to the internet, with logs looking
this like:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Thanks to the &lt;a href="https://asahilinux.org/2024/10/aaa-gaming-on-asahi-linux/"&gt;amazing
work&lt;/a&gt; of the &lt;a href="https://asahilinux.org/community/"&gt;Asahi
Team&lt;/a&gt;, &lt;a href="https://steampowered.com"&gt;Steam&lt;/a&gt; is
running on my arm64 Linux on my Apple M2. Unfortunately, it seems that a recent
update broke the ability for Steam to speak to the internet, with logs looking
this like:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Checking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Checking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fastly&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steamstatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_ubuntu12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Downloading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;akamai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steamstatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_ubuntu12&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;akamai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steamstatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_ubuntu12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Downloading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steamstatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_ubuntu12&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steamstatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_ubuntu12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DownloadManifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exhausted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hosts&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Failed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Saving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;jvoisin&lt;/span&gt;&lt;span class="o"&gt;/.&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Steam&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;steam_client_metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Verifying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installation&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Verifying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;checksums&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Verifying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installation&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Verifying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installation&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A quick look at &lt;code&gt;journalctl&lt;/code&gt; shows that SELinux doesn't like what &lt;code&gt;passt&lt;/code&gt; is
trying to do:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Mar 17 23:07:26 chernabog audit[2093303]: AVC avc:  denied  { execstack } for  pid=2093303 comm=&amp;quot;passt&amp;quot; scontext=unconfined_u:unconfined_r:passt_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:passt_t:s0-s0:c0.c1023 tclass=process permissive=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://passt.top/passt/about/"&gt;Passt&lt;/a&gt; is a piece of software providing
user-mode networking for virtual machines, and apparently got stuck in the 90s
because it requires an executable stack, sigh.&lt;/p&gt;
&lt;p&gt;The easiest way to fix this is to &lt;del&gt;read the ~250-pages long &lt;a href="https://github.com/SELinuxProject/selinux-notebook"&gt;SELinux
notebook&lt;/a&gt;&lt;/del&gt; use
&lt;a href="https://linux.die.net/man/8/ausearch"&gt;&lt;code&gt;ausearch&lt;/code&gt;&lt;/a&gt; and to throw its output to
&lt;a href="https://linux.die.net/man/1/audit2allow"&gt;&lt;code&gt;audit2allow&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;# &lt;/span&gt;ausearch&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;passt&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--raw&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;audit2allow&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;local-passt
&lt;span class="go"&gt;******************** IMPORTANT ***********************&lt;/span&gt;
&lt;span class="go"&gt;To make this policy package active, execute:&lt;/span&gt;

&lt;span class="go"&gt;semodule -i local-passt.pp&lt;/span&gt;

&lt;span class="gp"&gt;# &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;local-passt.te

&lt;span class="go"&gt;module local-passt 1.0;&lt;/span&gt;

&lt;span class="go"&gt;require {&lt;/span&gt;
&lt;span class="go"&gt;    type passt_t;&lt;/span&gt;
&lt;span class="go"&gt;    class udp_socket getattr;&lt;/span&gt;
&lt;span class="go"&gt;    class process { execmem execstack };&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="o"&gt;=============&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;passt_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==============&lt;/span&gt;

&lt;span class="gp"&gt;#&lt;/span&gt;!!!!&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;avc&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;allowed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;current&lt;span class="w"&gt; &lt;/span&gt;policy
&lt;span class="go"&gt;allow passt_t self:process execstack;&lt;/span&gt;
&lt;span class="go"&gt;allow passt_t self:process execmem;&lt;/span&gt;

&lt;span class="gp"&gt;#&lt;/span&gt;!!!!&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;avc&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;allowed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;current&lt;span class="w"&gt; &lt;/span&gt;policy
&lt;span class="go"&gt;allow passt_t self:udp_socket getattr;&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;semodule&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;local-passt.pp
&lt;span class="go"&gt;libsemanage.semanage_direct_install_info: Overriding local-passt module at lower priority 300 with module at priority 400.&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that's it, Steam should now be able to reach the information superhighway
again.&lt;/p&gt;</content><category term="sysadmin"></category></entry><entry><title>"Have I Been Stalked" post-mortem</title><link href="https://dustri.org/b/have-i-been-stalked-post-mortem.html" rel="alternate"></link><published>2026-02-11T00:30:00+01:00</published><updated>2026-02-11T00:30:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-02-11:/b/have-i-been-stalked-post-mortem.html</id><summary type="html">&lt;p&gt;With more and more databases from stalkerware being &lt;a href="https://techcrunch.com/?s=stalkerware"&gt;made freely
available&lt;/a&gt;, there were some internal
conversations at &lt;a href="https://echap.eu.org"&gt;Echap&lt;/a&gt; about what could be done with
them to help victims. Everyone knows &lt;a href="https://haveibeenpwned.com/"&gt;Have I Been
Pwned&lt;/a&gt;, the website where you can put your email
address and check if it appears in &lt;em&gt;popular …&lt;/em&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;With more and more databases from stalkerware being &lt;a href="https://techcrunch.com/?s=stalkerware"&gt;made freely
available&lt;/a&gt;, there were some internal
conversations at &lt;a href="https://echap.eu.org"&gt;Echap&lt;/a&gt; about what could be done with
them to help victims. Everyone knows &lt;a href="https://haveibeenpwned.com/"&gt;Have I Been
Pwned&lt;/a&gt;, the website where you can put your email
address and check if it appears in &lt;em&gt;popular&lt;/em&gt; database leaks. Wouldn't it be
nice to do something similar, but for stalkerware?&lt;/p&gt;
&lt;p&gt;I built a prototype in &lt;a href="https://flask.palletsprojects.com/"&gt;Flask&lt;/a&gt;, but quickly
switched to &lt;a href="https://djangoproject.com/"&gt;Django&lt;/a&gt; because of its autogenerated
administration interface. It also comes with a lot of nice things like a
declarative data model, integrated form validation, and so on.
For the database, &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; was suggested, but
I picked &lt;a href="https://sqlite.org"&gt;sqlite&lt;/a&gt; instead, as not &lt;em&gt;that&lt;/em&gt; much traffic is expected,
and except for new leaks incorporation, access will be purely read-only. Also,
easy backups. To prevent enumeration/bruteforce and to keep bots in check,
&lt;a href="https://hcaptcha.com/"&gt;hcaptcha&lt;/a&gt; is alright, and it'll likely have
a better accessibility than something homegrown.&lt;/p&gt;
&lt;p&gt;The real questions were more about privacy than about the technical stack.
First of all, the decision was made of allowing users to query the database via
&lt;a href="https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity"&gt;IMEI&lt;/a&gt;,
and not phone numbers, since the later is usually public, and we don't want
anyone to check their &lt;em&gt;friends&lt;/em&gt; devices. Another important piece was data
minimization: we already have databases with a ton of data in them, and
there is nothing we can do to reduce those, but what we &lt;em&gt;can do&lt;/em&gt; is to only
put the smallest possible subset of this data on the website, to tell people if
their device was infected, when, by what, and possibly by whom.&lt;/p&gt;
&lt;p&gt;The IMEI is stored &lt;a href="https://en.wikipedia.org/wiki/SHA-2"&gt;hashed&lt;/a&gt;, not for
security purposes as the number of possible IMEI is around 10¹⁴ making the
whole keyspace absolutely bruteforceable, but so that an administrator doing
maintenance/debugging doesn't see them in clear-text. Another nice trick to
prevent the website from knowing who is checking what device, is to generate a
dozen random IMEI client-side, and send them along with the real IMEI the user
is checking, so that it could only be inferred, if someone wanted to look after
the fact, that a given IP address checked a given set of IMEI. Of course, the
IMEI-checking queries are made via &lt;code&gt;POST&lt;/code&gt;, and thus don't show up in the logs.&lt;/p&gt;
&lt;p&gt;Speaking of data, the database leaks were either publicly available, or sent
to us by third parties. There is no plans to share them with anyone.&lt;/p&gt;
&lt;p&gt;While I'm the one who wrote the code, this project is also the brainchild of
&lt;a href="https://esther.codes/"&gt;Esther&lt;/a&gt;, who provided technical expertise on "
Django and stuff in production", back'n'forth conversations on everything
privacy-related, as well as an early Django-based prototype.&lt;/p&gt;
&lt;p&gt;The website looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dustri.org/b/images/hibs.png"&gt;&lt;img alt="main page" src="https://dustri.org/b/images/hibs.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dustri.org/b/images/hibsfaq.png"&gt;&lt;img alt="faq page" src="https://dustri.org/b/images/hibsfaq.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now where can you find this marvel of modern engineering? Well you can't
(albeit I can provide the code if you really want.) It was eventually decided to not
go through with the project for several reasons, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It's a legal minefield that Echap, as a miniscule non-profit, isn't equipped
   at all to navigate.&lt;/li&gt;
&lt;li&gt;On haveibeenpwned, the remediation steps are straightforward: change your
   password, email you &lt;a href="https://en.wikipedia.org/wiki/National_data_protection_authority"&gt;national data protection
   authorities&lt;/a&gt;,
   go on with your life. For stalkerware, not so much; it's a traumatic event
   to be told that one's phone has been spied on, and removing the stalkerware
   might tip the attacker and worsen the situation. Moreover, Echap's is
   only providing technical expertise/support/training/documentation to
   entities doing actual assistance, not the assistance itself.&lt;/li&gt;
&lt;li&gt;While I'm more-or-less confident in my technical skills, hosting such
   sensitive data on the internet makes is the kind of thing that keeps you up
   at night.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It was an interesting idea, with exciting privacy challenges, but in the end,
I'm glad it was shelved. But rest assured that other things have being worked
on ;)&lt;/p&gt;</content><category term="web"></category></entry><entry><title>Antide's Law</title><link href="https://dustri.org/b/antides-law.html" rel="alternate"></link><published>2026-02-04T21:00:00+01:00</published><updated>2026-02-04T21:00:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-02-04:/b/antides-law.html</id><summary type="html">&lt;p&gt;A friend of mine, namely &lt;a href="https://xark.es/"&gt;Antide "xarkes" Petit&lt;/a&gt;, came up with
a pretty good rule of thumb that I think should be elevated into a law,
Antide's Law:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If it's unclear what a cyber-security company is doing, what they're doing
is pretty clear.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, take a look at &lt;a href="https://www.offensivecon.org/"&gt;Offensive …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A friend of mine, namely &lt;a href="https://xark.es/"&gt;Antide "xarkes" Petit&lt;/a&gt;, came up with
a pretty good rule of thumb that I think should be elevated into a law,
Antide's Law:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If it's unclear what a cyber-security company is doing, what they're doing
is pretty clear.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, take a look at &lt;a href="https://www.offensivecon.org/"&gt;Offensive Con&lt;/a&gt;
&lt;a href="https://www.offensivecon.org/sponsors/2025.html"&gt;2025&lt;/a&gt; and
&lt;a href="https://www.offensivecon.org/sponsors/2024.html"&gt;2024&lt;/a&gt; sponsors. Amongst them,
you can find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.catalystsecurity.com/"&gt;Catalyst Security&lt;/a&gt;:
  "Catalyst Security is a growing team of highly experienced vulnerability
  researchers, working on solving the most challenging problems in support of
  our customers."&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.safateam.com/about"&gt;SAFA&lt;/a&gt;: "Leveraging human and machine
  intelligence, SAFA zooms into cyber threat flashpoints, keeping you protected
  now and into the future." as well as "SAFA’s progressive approach to
  cybersecurity means we’re not content to see clients tread water; we strive
  to keep them ahead of cyber threats. Our in-house research, along with the
  latest technologies, lets you see what’s coming and proactively adapt."&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vigilantlabs.com/"&gt;Vigilant Labs&lt;/a&gt;: "It's a need to know thing."&lt;/li&gt;
&lt;li&gt;&lt;a href="https://binarygecko.com/"&gt;Binary Gecko&lt;/a&gt;: "Binary Gecko GmbH provides tailor
  made cybersecurity solutions and services. Our international team is made up
  of world class, highly technical professionals with a proven track record in
  the field. We strive to tackle every problem with a holistic and in depth
  approach."&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.secfence.com/aboutus.html"&gt;Secfence&lt;/a&gt;: "Secfence has been the
  pioneer of Information Security in India for almost a decade. We are a
  research- based organization and we take pride in innovating and pioneering
  many techniques and methodologies in Information Security. Along with our
  in-house research teams, we have formed global alliances to bring the latest
  and the best technology to our clients."&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's not obvious what services those companies are providing, so it's pretty
obvious what services they're providing: exploits/capabilities.&lt;/p&gt;
&lt;p&gt;Of course, it isn't a universal law. For one, it doesn't apply to
megacorporations, as they too tend to have meaningless blurbs on their websites
as well. For example, while "&lt;a href="https://www.capgemini.com/about-us/"&gt;Capgemini&lt;/a&gt;
helps businesses imagine their future and make it real with AI, technology and
people." doesn't means much, what they're providing is information technology
consulting and outsourcing, like &lt;a href="https://www.usaspending.gov/award/CONT_IDV_70CDCR26D00000015_7012"&gt;providing skip tracing
services for enforcement and removal operations for the
ICE&lt;/a&gt;.
Also, sometimes, it's simply a company being abysmally bad at marketing.&lt;/p&gt;
&lt;p&gt;Note that the contrapositive isn't true, a minority of companies are pretty
open about what they're doing, like
&lt;a href="https://www.crowdfense.com/about-us/"&gt;CrowdFense&lt;/a&gt; or
&lt;a href="https://www.epsilon-sec.com/what-we-do"&gt;Epsilon&lt;/a&gt;. And finally, some companies
like &lt;a href="https://zerodium.com/"&gt;Zerodium&lt;/a&gt; are so (in)famous that everyone knows
more or less what they're doing.&lt;/p&gt;</content><category term="security"></category></entry><entry><title>Snuffleupagus 0.13.0 - Elephas</title><link href="https://dustri.org/b/snuffleupagus-0130-elephas.html" rel="alternate"></link><published>2026-01-07T12:00:00+01:00</published><updated>2026-01-07T12:00:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-01-07:/b/snuffleupagus-0130-elephas.html</id><summary type="html">&lt;p&gt;&lt;a href="https://snuffleupagus.readthedocs.org"&gt;&lt;img alt="snuffleupagus logo" src="https://dustri.org/b/images/sp.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I just published a new release of
&lt;a href="https://github.com/jvoisin/snuffleupagus/releases/tag/v0.13.0"&gt;Snuffleupagus&lt;/a&gt;,
the hardening module for php7+ and php8+,
version &lt;code&gt;0.13.0&lt;/code&gt;, codename "Elephas",
named after the &lt;a href="https://en.wikipedia.org/wiki/Elephas"&gt;genus of elephants&lt;/a&gt;.
There aren't any new flashing features, only bug fixes, PHP85 support,
minor improvements, and a security fix for
&lt;a href="https://github.com/jvoisin/snuffleupagus/security/advisories/GHSA-c4ch-xw5p-2mvc"&gt;CVE-2026-22034&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://github.com/thomas-chauchefoin-tob"&gt;Thomas Chauchefoin …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://snuffleupagus.readthedocs.org"&gt;&lt;img alt="snuffleupagus logo" src="https://dustri.org/b/images/sp.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I just published a new release of
&lt;a href="https://github.com/jvoisin/snuffleupagus/releases/tag/v0.13.0"&gt;Snuffleupagus&lt;/a&gt;,
the hardening module for php7+ and php8+,
version &lt;code&gt;0.13.0&lt;/code&gt;, codename "Elephas",
named after the &lt;a href="https://en.wikipedia.org/wiki/Elephas"&gt;genus of elephants&lt;/a&gt;.
There aren't any new flashing features, only bug fixes, PHP85 support,
minor improvements, and a security fix for
&lt;a href="https://github.com/jvoisin/snuffleupagus/security/advisories/GHSA-c4ch-xw5p-2mvc"&gt;CVE-2026-22034&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://github.com/thomas-chauchefoin-tob"&gt;Thomas Chauchefoin&lt;/a&gt; for
finding the vulnerability and producing a &lt;a href="https://github.com/jvoisin/snuffleupagus/security/advisories/GHSA-c4ch-xw5p-2mvc"&gt;comprehensive
write-up&lt;/a&gt;.
While being assigned CVE is never fun, it's also a sign that people are
interested in your software enough to spend the time to looks for bugs.
Moreover, I guess it was a learning opportunity to be on the other side for
once. As usual, the CVSS score (9.2/10) is bullshit by design as there is no
way to properly account for the required conditions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Snuffleupagus' &lt;a href="https://snuffleupagus.readthedocs.io/config.html#upload-validation"&gt;&lt;code&gt;upload_validation&lt;/code&gt;&lt;/a&gt; to be enabled, which isn't the default configuration.&lt;/li&gt;
&lt;li&gt;To be manually configured to use &lt;a href="https://github.com/derickr/vld"&gt;&lt;code&gt;vld&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To have the &lt;code&gt;vld&lt;/code&gt; module unavailable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nevertheless, as PHP isn't erroring out on missing modules (!), whatever
update/change breaking &lt;code&gt;vld&lt;/code&gt; might silently result in a catastrophic remote
code execution, so please do update. The fix is
&lt;a href="https://github.com/jvoisin/snuffleupagus/commit/9278dc77bab2a219e770a1b31dd6797bc9070e37"&gt;dead-simple&lt;/a&gt;
and can easily be backported if that's your kink.&lt;/p&gt;
&lt;h3&gt;Changelog&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compatibility with PHP8.5&lt;/li&gt;
&lt;li&gt;Add the possibility to log to a file&lt;/li&gt;
&lt;li&gt;Improve .drop() logging reliability when &lt;code&gt;set_error_handler&lt;/code&gt; is used&lt;/li&gt;
&lt;li&gt;Improve simulation mode for &lt;code&gt;unserialize()&lt;/code&gt; when no HMAC key is provided&lt;/li&gt;
&lt;li&gt;Fix a possible arbitrary code execution on misconfigured &lt;code&gt;upload_validation&lt;/code&gt; deployments (&lt;a href="https://github.com/jvoisin/snuffleupagus/security/advisories/GHSA-c4ch-xw5p-2mvc"&gt;CVE-2026-22034&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As usual, if you want to help, we have some
&lt;a href="https://github.com/jvoisin/snuffleupagus/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22"&gt;low hanging fruits&lt;/a&gt; ♥&lt;/p&gt;
&lt;p&gt;See you in your PHP stack!&lt;/p&gt;</content><category term="php"></category></entry><entry><title>fortify-headers 3.0.1</title><link href="https://dustri.org/b/fortify-headers-301.html" rel="alternate"></link><published>2026-01-05T17:30:00+01:00</published><updated>2026-01-05T17:30:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2026-01-05:/b/fortify-headers-301.html</id><summary type="html">&lt;p&gt;There is a new minor release of &lt;a href="https://git.2f30.org/fortify-headers/"&gt;fortify-headers&lt;/a&gt;,
namely 3.0.1. Minor releases means no new features, only bug fixes.&lt;/p&gt;
&lt;p&gt;The C language doesn't really have the notion of namespaces: all symbols,
except those marked as &lt;code&gt;static&lt;/code&gt; are exposed. To mitigate the possibility of
collisions, it's a good practise …&lt;/p&gt;</summary><content type="html">&lt;p&gt;There is a new minor release of &lt;a href="https://git.2f30.org/fortify-headers/"&gt;fortify-headers&lt;/a&gt;,
namely 3.0.1. Minor releases means no new features, only bug fixes.&lt;/p&gt;
&lt;p&gt;The C language doesn't really have the notion of namespaces: all symbols,
except those marked as &lt;code&gt;static&lt;/code&gt; are exposed. To mitigate the possibility of
collisions, it's a good practise to prefix exported symbols with an
library-specific identifier, like &lt;code&gt;xml&lt;/code&gt; for libxml2 (eg. &lt;code&gt;xmlReadFile&lt;/code&gt;), 
&lt;code&gt;SSL&lt;/code&gt; for OpenSSL (eg. &lt;code&gt;SSL_library_init&lt;/code&gt;) and so on. &lt;a href="https://en.cppreference.com/w/c/language/identifier.html"&gt;Symbols starting with an
underscore followed by either an upper-case letter or another underscore are
implementation-reserved&lt;/a&gt;.
I was a bit cocky, and assumed that since fortify-headers is kind of part of
the implementation, I could name macros &lt;code&gt;__format&lt;/code&gt;, &lt;code&gt;__warning_if&lt;/code&gt;, &lt;code&gt;__access&lt;/code&gt;,
… Unfortunately, this lead to a collision with LLVM's libcxx, as it defines
a &lt;code&gt;__format&lt;/code&gt; macro in its C++ locale header (&lt;code&gt;/usr/include/c++/v1/locale&lt;/code&gt;).
This &lt;a href="https://github.com/jvoisin/fortify-headers/issues/76"&gt;was found&lt;/a&gt; by
&lt;a href="https://hacktivis.me/"&gt;Haelwenn (lanodan) Monnier&lt;/a&gt;, when he tried to make use
of fortify-headers on Gentoo. The fix is quite straightforward: make use of a
fortify-headers specific prefix, resulting in &lt;code&gt;__fortify_format&lt;/code&gt;,
&lt;code&gt;__fortify_warning_if&lt;/code&gt;, &lt;code&gt;__fortify_access&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The release is available on &lt;a href="https://github.com/jvoisin/fortify-headers/releases/tag/3.0.1"&gt;github&lt;/a&gt;,
and the tag has been pushed on &lt;a href="https://git.2f30.org/fortify-headers/refs.html"&gt;2f30&lt;/a&gt;
as well.&lt;/p&gt;</content><category term="security"></category></entry><entry><title>2025 in retrospect</title><link href="https://dustri.org/b/2025-in-retrospect.html" rel="alternate"></link><published>2025-12-31T23:59:00+01:00</published><updated>2025-12-31T23:59:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-12-31:/b/2025-in-retrospect.html</id><summary type="html">&lt;p&gt;In 2025, I did, amongst other things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read some books:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Torture_Taxi"&gt;Torture Taxi: On the Trail of the CIA's Rendition Flights&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mattpotter.com/latest-book-outlaws-inc/"&gt;Outlaws Inc&lt;/a&gt;: a lot of storytelling, not much meat, still interesting.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Fran%C3%A7ois_B%C3%A9gaudeau"&gt;Boniments&lt;/a&gt;: hard to find anything hiding under so much sarcasm.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://theintercept.com/drone-papers/the-assassination-complex/"&gt;The Assassination Complex&lt;/a&gt;: drone-powered war crimes made in USA …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;In 2025, I did, amongst other things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read some books:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Torture_Taxi"&gt;Torture Taxi: On the Trail of the CIA's Rendition Flights&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mattpotter.com/latest-book-outlaws-inc/"&gt;Outlaws Inc&lt;/a&gt;: a lot of storytelling, not much meat, still interesting.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Fran%C3%A7ois_B%C3%A9gaudeau"&gt;Boniments&lt;/a&gt;: hard to find anything hiding under so much sarcasm.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://theintercept.com/drone-papers/the-assassination-complex/"&gt;The Assassination Complex&lt;/a&gt;: drone-powered war crimes made in USA.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Catcher_in_the_Rye"&gt;The Catcher in the Rye&lt;/a&gt;: anyone who wants to ban this book didn't read it.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Trevor_Paglen"&gt;Blank Spots on the Map: The Dark Geography of the Pentagon's Secret World&lt;/a&gt;: fascinating.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://howtoarguewithameateater.com/"&gt;How to Argue With a Meat Eater (and win every time&lt;/a&gt;: the amount of bullshit the author had to deal with is impressive.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/29501956-art-crime-and-its-prevention"&gt;Art Crime and its Prevention: A Handbook for Collectors and Art Professionals&lt;/a&gt;,
  equally boring and cocky, gave up around the middle of it.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.versobooks.com/products/688-breaking-things-at-work"&gt;Breaking Things at Work: The Luddites Are Right About Why You Hate Your Job&lt;/a&gt;,
  trying to shove everything through a Marxist lens, felt tedious.&lt;/li&gt;
&lt;li&gt;A handful of manga:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Gantz"&gt;Gantz&lt;/a&gt;: didn't age very well.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Deadman_Wonderland"&gt;Deadman Wonderland&lt;/a&gt;, uninteresting, gave up after 6 tomes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/D.Gray-man"&gt;D.Gray-man&lt;/a&gt;: great drawings, everything else is tedious, gave up around book 10.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Climber_(manga)"&gt;Kokō no Hito&lt;/a&gt;: great topic, terrible realisation on every level, gave up after 4 tomes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Mashle"&gt;Mashle: Magic and Muscles&lt;/a&gt;: something like "Harry Potter, but the dude can't do magic and has muscles instead." Refreshingly funny.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some &lt;a href="https://en.wikipedia.org/wiki/Warhammer_40,000"&gt;Warhammer 40,000&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Planetkill_(Anthology)"&gt;Planetkill&lt;/a&gt;, nice bunch of novellas.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Darkness_in_the_Blood_(Novel)"&gt;Darkness in the Blood&lt;/a&gt;: &lt;a href="https://wh40k.lexicanum.com/wiki/Mephiston"&gt;Mephiston&lt;/a&gt;-wanking&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Elemental_Council_(Novel)"&gt;Elemental Council&lt;/a&gt;: properly written Tau novel.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Angron:_Slave_of_Nuceria_(Novel)"&gt;Angron: Slave of Nuceria&lt;/a&gt;, the birth of Angron's tragedy.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Kh%C3%A2rn:_Eater_of_Worlds_(Novel)"&gt;Khârn: Eater of Worlds&lt;/a&gt;, Khârn's post-Heresy comeback.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Ordo_Sinister_(Short_Story)"&gt;Ordo Sinister&lt;/a&gt;: short story about the eponymous &lt;a href="https://wh40k.lexicanum.com/wiki/Ordo_Sinister"&gt;Ordo Sinister&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/No_Good_Men_(Anthology)"&gt;No Good Men&lt;/a&gt;: great &lt;a href="https://wh40k.lexicanum.com/wiki/Warhammer_Crime"&gt;Warhammer Crime&lt;/a&gt; short stories anthology &lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Steel_Tread_(Novel)"&gt;Steel Tread&lt;/a&gt;, a tank commander story wrapping up a planetary war, really nice.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Day_of_Ascension_(Novel)"&gt;Day of Ascension&lt;/a&gt;: a novel from the point of view of a Genestealer cult, refreshing.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Leviathan_(Novel)"&gt;Leviathan&lt;/a&gt;: Space Marines against Tyranids trying to save the day on a dying planet.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/The_Oubliette_(Novel)"&gt;The Oubliette&lt;/a&gt;: with a Planetary governor balancing on the edge of heresy, really good.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Scions_of_the_Emperor_(Anthology)"&gt;Scions of the Emperor&lt;/a&gt;: &lt;a href="https://wh40k.lexicanum.com/wiki/Horus_Heresy:_The_Primarchs"&gt;Horus Heresy's Primarchs&lt;/a&gt;
  short stories anthology, pretty great.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Interceptor_City_(Novel)"&gt;Interceptor City&lt;/a&gt;: yet another chef d'œuvre by Dan Abnett featuring the &lt;a href="https://wh40k.lexicanum.com/wiki/Imperial_Navy"&gt;Imperial Navy&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/The_Silent_King_(Novel)"&gt;The Silent King&lt;/a&gt;: wrapping up the &lt;a href="https://wh40k.lexicanum.com/wiki/Dawn_of_Fire_(Series)"&gt;Dawn of Fire&lt;/a&gt; series, nice to read the Imperium lose for once.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Blood_of_the_Emperor_(Anthology)"&gt;Blood of the Emperor&lt;/a&gt;: anthology of small novellas about the Primarchs, some are great, others less so.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Angron:_The_Red_Angel_(Novel)"&gt;Angron: The Red Angel&lt;/a&gt;, about the crushing of a World Eater leader's dreams thanks to Angron's return.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/The_King_of_the_Spoil_(Novel)"&gt;The King of the Spoil&lt;/a&gt;: commoners fomenting a civil war, with nested political and judicial points of view.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Oaths_of_Damnation_(Novel)"&gt;Oaths of Damnation&lt;/a&gt;: bolter porn featuring the Exorcists chapter, with a terrific intro and a terrible ending.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Deathworlder_(Novel)"&gt;Deathworlder&lt;/a&gt;: great &lt;a href="https://wh40k.lexicanum.com/wiki/Astra_Militarum"&gt;Astra Militarum&lt;/a&gt; novel,
  with properly written, badass and charismatic female protagonists.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Urdesh:_The_Serpent_and_the_Saint_(Novel)"&gt;Urdesh: The Serpent and the Saint&lt;/a&gt;
  and &lt;a href="https://wh40k.lexicanum.com/wiki/Urdesh:_The_Magister_and_the_Martyr_(Novel)"&gt;Urdesh: The Magister and the Martyr&lt;/a&gt;, nice to see ocean-themed marines.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Daemonhammer_(Novel)"&gt;Daemonhammer&lt;/a&gt;: a novel about an unsubtle inquisitor, nice but not groundbreaking, characters felt a tad undeveloped.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Gothic_War_(Novel_Series)#Execution_Hour"&gt;Execution Hour&lt;/a&gt;, great book about the end of a Planet told by a vessel of the evacuation fleet, too bad the end felt rushed.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Era_of_Ruin_(Anthology)"&gt;Era of Ruin&lt;/a&gt;: an anthology of novellas about what happens after The End and the Death, unfortunately none of them were super-memorable.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wh40k.lexicanum.com/wiki/Hand_of_Abaddon_(Novel)"&gt;Hand of Abaddon&lt;/a&gt;, always nice to see the setting moving forward, even though the novel
  was a tad too tedious/scattered all around the place for my taste.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Did a couple of job interviews:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://synacktiv.com/en"&gt;Synacktiv&lt;/a&gt;, for a &lt;a href="https://synacktiv.com/developpeur-doutils-red-team"&gt;red team tooling
  developer&lt;/a&gt;
  position. I passed the (fun) technical challenge, but didn't finish the
  interview process as I signed elsewhere.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://wikimediafoundation.org/"&gt;Wikimedia Foundation&lt;/a&gt;, for a &lt;a href="https://job-boards.greenhouse.io/wikimedia/jobs/6126716?gh_src=f74a1ed11us"&gt;Staff Software Security
    Engineer&lt;/a&gt;
    position. I got an offer that I declined, as I got a better one by
    another company 30min after getting this one.&lt;/li&gt;
&lt;li&gt;███████████, for a Head of Security and IT position, which was
  remote-but-a-couple-of-days-a-week-in-Paris, managing 1.5 juniors, for
  around 3 times less than my current salary. The phone call was &lt;em&gt;awkward&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zellic.io/"&gt;Zellic&lt;/a&gt;, for a
  &lt;a href="https://zellic-inc.notion.site/Security-Researcher-568f73b944c44982a234a1cae6530581?pvs=25"&gt;security researcher
  position&lt;/a&gt;,
  but my &lt;a href="https://en.wikipedia.org/wiki/Solidity"&gt;solidity&lt;/a&gt; auditing skills
  were too weak, and I thus failed the really cool hiring challenge. But they
  offered me to continue the interview process for a &lt;a href="https://zellic-inc.notion.site/Software-Engineer-15175f108125806e9aa0e78e27a65b5c"&gt;software engineer/sysadmin
  position&lt;/a&gt;
  instead. I didn't give it a try it, as I already signed elsewhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Played some video games:&lt;ul&gt;
&lt;li&gt;On a computer:&lt;ul&gt;
&lt;li&gt;A bit of &lt;a href="https://en.wikipedia.org/wiki/Warhammer_40%2C000%3A_Space_Marine_2"&gt;Space Marines 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Warhammer_40,000:_Darktide"&gt;Darktide&lt;/a&gt;,
  mostly with the 2 new classes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Clair_Obscur:_Expedition_33"&gt;Clair Obscur: Expedition 33&lt;/a&gt;,
  usually not a big fan of JRPG, but this game is nothing short of amazing.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Age_of_Wonders_4"&gt;Age of Wonders 4&lt;/a&gt;:
  great 4X game, which while not being my favourite genre at all,
  was a ton of fun.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Witchfire"&gt;Witchfire&lt;/a&gt;: hands down the
  FPS of the year for me. Great setting, great gameplay, visually
  astonishing, and a complete and utter lack of bullshit DLSS.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Mutant_Year_Zero:_Road_to_Eden"&gt;Mutant Year Zero: Road to
  Eden&lt;/a&gt;,
  a chill post-apocalyptic variant on
  &lt;a href="https://en.wikipedia.org/wiki/XCOM"&gt;XCOM&lt;/a&gt;, without the tedious
  base-building parts and with some neat stealth element.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Ready_or_Not_(video_game)"&gt;Ready or Not&lt;/a&gt;: the spiritual successor to SWAT 4, 
but felt unfortunately a bit clunky and unfinished. Moreover, it
unfortunately felt like another "kill the bad guys!" game, instead of
playing a law-abiding officer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On a glorious steam deck:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Inscryption"&gt;Inscryption&lt;/a&gt;, gave up after the first act.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Balatro"&gt;Balatro&lt;/a&gt;, great game, but too much luck involved for my taste.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Precinct_(video_game)"&gt;The Precinct&lt;/a&gt;, I'm usually not a big fan of cops™,
  but playing GTA2 from the point of view of one, with proper penalties
  for not following due process is surprisingly nice.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Listened to &lt;a href="https://listenbrainz.org/user/jvoisin/year-in-music/2025/"&gt;some music&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Attended some concerts:&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://fr.wikipedia.org/wiki/Svinkels"&gt;Svinkels&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Alcest"&gt;Alcest&lt;/a&gt; and &lt;a href="https://bruitofficial.bandcamp.com/"&gt;BRUIT ≤&lt;/a&gt;, with the latter being a really good surprise.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nooneisinnocent.net/"&gt;No One is innocent&lt;/a&gt;
&lt;a href="https://www.fractaluniverseband.com/"&gt;Fractal Universe&lt;/a&gt;
&lt;a href="https://www.tamboursdubronx.com/home"&gt;Les tambours du bronx&lt;/a&gt; (opened with
Sepultura's Bloody Roots, and closed with Rob Zombie's American Witch!),
and &lt;a href="https://shaarghot.bigcartel.com/"&gt;Shaârghot&lt;/a&gt;, as the 
&lt;a href="https://bocksons.com/programmation/"&gt;Boksons&lt;/a&gt; festival. Oh and we sung
along while going back to the car on &lt;a href="https://earlymaggots.com/"&gt;Early Maggots&lt;/a&gt;
playing some classic Spliknot tracks in the distance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Contributed to a couple of projects:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rapid7/metasploit-framework/pulls?q=author%3Ajvoisin+created%3A%3E2024+"&gt;metasploit&lt;/a&gt;
  and &lt;a href="https://github.com/rapid7/metasploit-payloads/pull/714"&gt;metasploit-payloads&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/miniflux/v2/pulls?q=is%3Apr+author%3Ajvoisin+created%3A%3E2024"&gt;miniflux&lt;/a&gt;,
  with around 200 (!) pull-request merged this year alone.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Automattic/harper/pulls?q=author%3Ajvoisin+created%3A%3E2024+"&gt;harper&lt;/a&gt;,
  a trivial low-hanging things to make debugging easier, and &lt;a href="https://github.com/Automattic/harper/issues?q=is%3Aissue%20author%3Ajvoisin"&gt;opened a bunch
  of bugs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://alpinelinux.org"&gt;Alpine Linux&lt;/a&gt;,
   by being a &lt;a href="https://pkgs.alpinelinux.org/packages?name=&amp;amp;branch=edge&amp;amp;repo=&amp;amp;arch=&amp;amp;maintainer=Julien+Voisin"&gt;package maintainer&lt;/a&gt;,
   &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests?scope=all&amp;amp;state=merged&amp;amp;author_username=jvoisin"&gt;sending a handful of merge-requests&lt;/a&gt;,
   and &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/work_items/17822"&gt;trying to get rid of python-six&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nos-oignons.net/"&gt;Nos oignons&lt;/a&gt;, as part of the administration
  council and the sysadmin team. We're now responsible for &lt;a href="https://nos-oignons.net/Services/index.en.html"&gt;a little bit
  more than 3%&lt;/a&gt;
  of the network's total capacity.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openmw.org"&gt;OpenMW&lt;/a&gt;, by maintaining the infrastructure.
  &lt;a href="https://mediawiki.org/wiki/MediaWiki"&gt;MediaWiki&lt;/a&gt;, that we're using for
  &lt;a href="https://wiki.openmw.org"&gt;our wiki&lt;/a&gt;, is not only annoying to
  keep up to date, but also to fight spam: doing SQL by hand isn't really
  state of the art abuse remediation, sigh. Let's hope that the combination
  of &lt;a href="https://hcaptcha.com/"&gt;hCaptcha&lt;/a&gt;, DNSBL from
  spamhaus.org/spamrats.com/0spam.org/z.mailspike.net, keyword-based
  blocklist, and clownflare
  will curb the tide. And because morons can't stop &lt;a href="https://drewdevault.com/2025/03/17/2025-03-17-Stop-externalizing-your-costs-on-me.html"&gt;externalizing their
  costs directly into our
  faces&lt;/a&gt;,
  I deployed &lt;a href="https://anubis.techaro.lol/"&gt;Anubis&lt;/a&gt; on the &lt;a href="https://forum.openmw.org/"&gt;forum&lt;/a&gt;
  and the &lt;a href="https://wiki.openmw.org"&gt;wiki&lt;/a&gt;, sigh.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kept on writing my book, reaching a bit more than 100.000 words.&lt;/li&gt;
&lt;li&gt;Went to the &lt;a href="https://grehack.fr/"&gt;Grehack&lt;/a&gt;, where I saw old friends and made new ones.&lt;/li&gt;
&lt;li&gt;Added possible subtitles to this blog, bringing their total number above 1500.&lt;/li&gt;
&lt;li&gt;Changed the &lt;a href="https://www.ssllabs.com/ssltest/analyze.html?d=dustri.org"&gt;TLS certificates for this website&lt;/a&gt; to use
  elliptic curves for the whole chain: enjoy marginally faster handshakes and equally marginally size reduction in certificates transmission!&lt;/li&gt;
&lt;li&gt;Bought a house in the &lt;a href="https://en.wikipedia.org/wiki/Doubs"&gt;East of France&lt;/a&gt;,
  feel free to come say hi. As a side-effect I learnt how to do some basic
  plumbing/electricity/wood-working/gardening/…&lt;/li&gt;
&lt;li&gt;Got a fully-remote job at &lt;a href="https://casaba.com/"&gt;Casaba Security&lt;/a&gt;. The first
  weeks were a bit odd for everyone, as the switch from from a megacorp to a
  small(er) structure was a bit rough, but in the end I'm quite happy working
  there.&lt;/li&gt;
&lt;li&gt;Spent a couple of months without internet at home, hence why this little
  corner of the internet was unreachable. Things are now back to normal, and I
  have fiber in my office. A big thank you to everyone who reached out to
  enquire if everything was alright &amp;lt;3.&lt;/li&gt;
&lt;li&gt;As part of a conscious effort to make the word a better and more welcoming
  place, I successfully changed my usage of expletives and insults to more
  inclusive ones. I also think that this provides a positive influence on my
  friends and family, leading by example. Newly used terms include "sac à merde"
  ("shitbag"), "va te faire cuire le cul" ("go get your ass cooked"),
  "va marcher sur des legos" ("go walk on
  legos"), "bête à bouffer du grillage" and "bête à bêcher de la flotte"
  ("wire-mesh-eater/water digging level of stupid"), … Do let me know if you
  have suggestions, I'd love to expand my range of possibility and nuances.&lt;/li&gt;
&lt;/ul&gt;</content><category term="misc"></category></entry><entry><title>Fixing the health and safety video loop during the Oculus Quest setup</title><link href="https://dustri.org/b/fixing-the-health-and-safety-video-loop-during-the-oculus-quest-setup.html" rel="alternate"></link><published>2025-12-23T14:45:00+01:00</published><updated>2025-12-23T14:45:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-12-23:/b/fixing-the-health-and-safety-video-loop-during-the-oculus-quest-setup.html</id><summary type="html">&lt;p&gt;I gifted an Oculus Quest (that I got as a gift a couple of years ago) to my
brother, but because we're in 2025 and &lt;em&gt;everything computer-related sucks&lt;/em&gt;, one
has to associate an online account with the device to make use of it. Imagine
having to do this to use …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I gifted an Oculus Quest (that I got as a gift a couple of years ago) to my
brother, but because we're in 2025 and &lt;em&gt;everything computer-related sucks&lt;/em&gt;, one
has to associate an online account with the device to make use of it. Imagine
having to do this to use a regular screen… Nevertheless, if you're trying to
factory-reset it and re-setup it, you'll end up having the (mandatory)
"health and safety video" stuck in a loop and you won't be able to finish the
process. This is because &lt;s&gt;Facebook&lt;/s&gt; Meta is a small underfunded
independent software company, and thus it sadly can't afford to make sure that
a $500 product sold 5 years ago can still be setup today. If you're foolish
enough to call the support, you'll likely be politely told to fuck off, so
don't bother.&lt;/p&gt;
&lt;p&gt;But I remember that when I played with it, the setup phase was trivial: odds
are that an upgrade of the (mandatory for setup) android app broke
compatibility with the device. Using an old version will likely work.
Unfortunately, as Google's Play Store doesn't allow one to install older
versions, for &lt;em&gt;SeCuRiTy ReAsOnS&lt;/em&gt;. So instead of being able to download what
we're looking for from a trusted source, we'll have to use something like
&lt;a href="https://en.uptodown.com/"&gt;uptodown&lt;/a&gt; to download the APK we're looking for,
sigh. I picked the &lt;a href="https://oculus-twilight.en.uptodown.com/android/download/1019180364"&gt;Oculus Quest
&lt;code&gt;276.0.0.15.109&lt;/code&gt;&lt;/a&gt;,
and it worked for me. Don't forget to click the "all variants" button on
uptodown to pick the right architecture (arm64-v8a or armeabi-v7a). If you
don't know which is the right one, don't worry: if you pick the wrong one, your
phone will tell you that it can't install it, and you'll simply have to install
the other one. Oh and also click &lt;code&gt;ignore&lt;/code&gt; when it prompts you to upgrade to a
newer version when you're using the app. Try to setup the Oculus quest again,
and you should no longer be blocked on the annoying video.&lt;/p&gt;
&lt;p&gt;Once the headset is
setup, the application can be updated to its latest version in the Google Play
Store, but you can remove it from your phone all the same since it's not needed
once the setup is complete. Odds are that having anything Meta-related
installed on your phone will give you cyber-cancer, steal your nudes and sell
every pieces of information it can collect to the everyone willing to buy them,
but you do you.&lt;/p&gt;
&lt;p&gt;If you're worried about installing random APK files from the interweb (as you
should), the file has been &lt;a href="https://www.virustotal.com/gui/file/17c8640668c699e91cef630a02819c9489186d84fa3ab9eac2e13c3599476b8c"&gt;uploaded to
VirusTotal&lt;/a&gt;,
and is signed by the certificate &lt;code&gt;331660b6dd3bd582f3dfd3cbae4546724668a021&lt;/code&gt;,
which is a correct &lt;a href="https://reports.exodus-privacy.eu.org/en/reports/644935/"&gt;Facebook
one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and since it's Christmas time, I'd recommend gifting &lt;a href="https://store.steampowered.com/app/546560/HalfLife_Alyx/"&gt;Half-Life:
Alyx&lt;/a&gt; to go with the
device, it's a great game.&lt;/p&gt;</content><category term="misc"></category></entry><entry><title>fortify-headers 3.0</title><link href="https://dustri.org/b/fortify-headers-30.html" rel="alternate"></link><published>2025-12-08T17:00:00+01:00</published><updated>2025-12-08T17:00:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-12-08:/b/fortify-headers-30.html</id><summary type="html">&lt;p&gt;In late 2022, I started to contribute to &lt;a href="https://git.2f30.org/fortify-headers"&gt;fortify-headers&lt;/a&gt;, and the original author, sin, was kind
enough to entrust the project to me.&lt;/p&gt;
&lt;p&gt;Unfortunately, I feel that I haven't lived up to the expectations,
both from others, but also mine. I enthusiastically piled more code on
top of it, instead …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In late 2022, I started to contribute to &lt;a href="https://git.2f30.org/fortify-headers"&gt;fortify-headers&lt;/a&gt;, and the original author, sin, was kind
enough to entrust the project to me.&lt;/p&gt;
&lt;p&gt;Unfortunately, I feel that I haven't lived up to the expectations,
both from others, but also mine. I enthusiastically piled more code on
top of it, instead of moving slowly and making sure that I wasn't
breaking anything. Sure, I added a test suite, but it can't cover every
edge-cases, especially when dealing with code used system-wide in
virtually all C packages/software. It also didn't help that I had a
"complicated" life those last couple of years.&lt;/p&gt;
&lt;p&gt;Now onto the good news: I now have some peace of mind and free time again,
meaning I can go back to try to properly maintain fortify-headers. I shelved
everything I added to it on an &lt;code&gt;experimental&lt;/code&gt; branch (so that nothing is lost,
including old releases that I did), and started clean on top a sin's latest
master again. I'm not happy about rewriting history, I think it was least worse
option in my opinion, versus having a big "revert" commit, or an interminable
daisy-chain of revert.&lt;/p&gt;
&lt;p&gt;So what's new in this &lt;a href="https://git.2f30.org/fortify-headers/refs.html"&gt;release
3.0&lt;/a&gt; compared to sin's version?
A handful of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A complete testsuite, running on github actions, with &lt;code&gt;-Wall -Wextra&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Clang support, thanks to q66&lt;/li&gt;
&lt;li&gt;&lt;code&gt;access&lt;/code&gt; and &lt;code&gt;format&lt;/code&gt; annotations&lt;/li&gt;
&lt;li&gt;A missing include in select.h was added&lt;/li&gt;
&lt;li&gt;wctomb was removed, as it was buggy&lt;/li&gt;
&lt;li&gt;Support for &lt;code&gt;swab&lt;/code&gt; was added&lt;/li&gt;
&lt;li&gt;a 64b fix for time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Attribution was of course kept, and everything is available on
https://git.2f30.org/fortify-headers/log.html and
https://github.com/jvoisin/fortify-headers (to use github CI). QA-wise, on top
of the testsuite, a full &lt;a href="https://openwrt.org"&gt;OpenWRT&lt;/a&gt; build is used as a
smoke test. This should prevent bugs from creeping in.&lt;/p&gt;
&lt;p&gt;I'd love if people of you could take a quick look at this new tentative, so
that I can ask downstream projects to give a new try at upgrading from 1.1.&lt;/p&gt;</content><category term="security"></category></entry><entry><title>Running the packaged *arr stack on Alpine</title><link href="https://dustri.org/b/running-the-packaged-arr-stack-on-alpine.html" rel="alternate"></link><published>2025-12-04T00:15:00+01:00</published><updated>2025-12-04T00:15:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-12-04:/b/running-the-packaged-arr-stack-on-alpine.html</id><summary type="html">&lt;p&gt;I've been running some parts of the &lt;a href="https://wiki.servarr.com/"&gt;*arr stack&lt;/a&gt;
on my hypervisor at home for quite some time now, but only recently did I
notice that they were &lt;a href="https://pkgs.alpinelinux.org/packages?name=*arr&amp;amp;branch=edge&amp;amp;repo=&amp;amp;arch=x86_64&amp;amp;origin=&amp;amp;flagged=&amp;amp;maintainer="&gt;packaged in
Alpine&lt;/a&gt;!
I trashed the container with all the carefully-deployed-by-hand binaries,
created a new one running &lt;a href="https://wiki.alpinelinux.org/wiki/Repositories#Edge"&gt;Alpine
Edge&lt;/a&gt;, ran &lt;code&gt;apk add …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been running some parts of the &lt;a href="https://wiki.servarr.com/"&gt;*arr stack&lt;/a&gt;
on my hypervisor at home for quite some time now, but only recently did I
notice that they were &lt;a href="https://pkgs.alpinelinux.org/packages?name=*arr&amp;amp;branch=edge&amp;amp;repo=&amp;amp;arch=x86_64&amp;amp;origin=&amp;amp;flagged=&amp;amp;maintainer="&gt;packaged in
Alpine&lt;/a&gt;!
I trashed the container with all the carefully-deployed-by-hand binaries,
created a new one running &lt;a href="https://wiki.alpinelinux.org/wiki/Repositories#Edge"&gt;Alpine
Edge&lt;/a&gt;, ran &lt;code&gt;apk add sonarr
radarr prowlarr&lt;/code&gt;, and…&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;~ # apk add sonarr radarr prowlarr&lt;/span&gt;
&lt;span class="go"&gt;ERROR: unable to select packages:&lt;/span&gt;
&lt;span class="go"&gt;  aspnetcore6-runtime (no such package):&lt;/span&gt;
&lt;span class="go"&gt;    required by: sonarr-4.0.16.2944-r0[aspnetcore6-runtime]&lt;/span&gt;
&lt;span class="go"&gt;~ #&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Urgh, the latest Sonarr release
(&lt;a href="https://github.com/Sonarr/Sonarr/releases/tag/v4.0.16.2944"&gt;v4.0.16.2944&lt;/a&gt;),
is still &lt;a href="https://github.com/Sonarr/Sonarr/blob/v4.0.16.2944/src/NzbDrone.Core/Sonarr.Core.csproj"&gt;running on .NET
6&lt;/a&gt;,
which isn't packaged anymore on Alpine Edge. Fortunately, one can do horribly
unsupported things like &lt;a href="https://wiki.alpinelinux.org/wiki/Repositories#Tagged_repository"&gt;mixing
repositories&lt;/a&gt;,
and have a &lt;code&gt;/etc/apk/repositories&lt;/code&gt; frankenfile looking like this:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpinelinux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpinelinux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;community&lt;/span&gt;
&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpinelinux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;

&lt;span class="nv"&gt;@main319&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpinelinux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="mf"&gt;.19&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="nv"&gt;@community319&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpinelinux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="mf"&gt;.19&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;community&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Installing Sonarr can then be done with &lt;code&gt;apk add sonar@community319
sonar-openrc@community319&lt;/code&gt;, launched via &lt;code&gt;service sonarr start&lt;/code&gt;, and … it
crashes after a couple of seconds. Running &lt;code&gt;service -d sonarr start&lt;/code&gt; tells us
that the binary being launched is &lt;code&gt;/usr/lib/sonarr/bin/Sonarr&lt;/code&gt;, so let's see
what happens when we run it manually:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sonarr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Sonarr&lt;/span&gt;
&lt;span class="n"&gt;You&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;must&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sonarr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Sonarr&lt;/span&gt;
&lt;span class="n"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x64&lt;/span&gt;
&lt;span class="n"&gt;Framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Microsoft.NETCore.App&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6.0.36&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;

&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frameworks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;were&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NETCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NETCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;Learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;more&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;aka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;

&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;aka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;applaunch&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NETCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;framework_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;x64&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;3.23&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x64&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alpine&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Alright, .NET version mismatch: we have 6.0.31 installed and the binary wants
6.0.36. The
&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/versions/selection#framework-dependent-apps-roll-forward"&gt;&lt;code&gt;DOTNET_ROLL_FORWARD&lt;/code&gt;&lt;/a&gt;
environment variable can be used to make a binary run on newer version of
the runtime, but not an older one. While we can't use 6.0.31, we have 8.0.22
installed for the rest of the *arr stack, so let's give it a try. Adding 
&lt;code&gt;DOTNET_ROLL_FORWARD=LatestMajor&lt;/code&gt; followed by &lt;code&gt;export DOTNET_ROLL_FORWARD&lt;/code&gt;
in &lt;code&gt;/etc/init.d/sonarr&lt;/code&gt; does the trick, and Sonarr is now working, huzzah!&lt;/p&gt;
&lt;p&gt;Once &lt;a href="https://github.com/Sonarr/Sonarr/tree/v5-develop"&gt;Sonarr 5.X&lt;/a&gt; is
released, I'll simply remove the &lt;code&gt;@community319/@main@319&lt;/code&gt; lines from
&lt;code&gt;/etc/apk/repositories&lt;/code&gt; and run &lt;code&gt;apk update; apk upgrade&lt;/code&gt; to get the version
compiled for modern packaged .NET.&lt;/p&gt;</content><category term="sysadmin"></category></entry><entry><title>IPv6 with a Freebox Pop and OPNSense</title><link href="https://dustri.org/b/ipv6-with-a-freebox-pop-and-opnsense.html" rel="alternate"></link><published>2025-11-30T15:00:00+01:00</published><updated>2025-11-30T15:00:00+01:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-11-30:/b/ipv6-with-a-freebox-pop-and-opnsense.html</id><summary type="html">&lt;p&gt;Because the &lt;a href="https://free.fr/freebox/"&gt;Freebox Pop&lt;/a&gt; is &lt;s&gt;an underpowered piece
of crap&lt;/s&gt; quite weak when it comes to
&lt;a href="https://en.wikipedia.org/wiki/Network_address_translation"&gt;NAT&lt;/a&gt;'ing anything
above 100Mbps, I decided to get a proper machine and slap
&lt;a href="https://opnsense.org/"&gt;OPNSense&lt;/a&gt; on it: I'm paying for the whole fiber, I'm
going to use the whole fiber.&lt;/p&gt;
&lt;p&gt;IPv4 was trivial: &lt;code&gt;Firewall …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Because the &lt;a href="https://free.fr/freebox/"&gt;Freebox Pop&lt;/a&gt; is &lt;s&gt;an underpowered piece
of crap&lt;/s&gt; quite weak when it comes to
&lt;a href="https://en.wikipedia.org/wiki/Network_address_translation"&gt;NAT&lt;/a&gt;'ing anything
above 100Mbps, I decided to get a proper machine and slap
&lt;a href="https://opnsense.org/"&gt;OPNSense&lt;/a&gt; on it: I'm paying for the whole fiber, I'm
going to use the whole fiber.&lt;/p&gt;
&lt;p&gt;IPv4 was trivial: &lt;code&gt;Firewall&lt;/code&gt; -&amp;gt; &lt;code&gt;NAT&lt;/code&gt; -&amp;gt; &lt;code&gt;Port Forward&lt;/code&gt;, and you're done. It
took me 5 minutes. &lt;a href="https://en.wikipedia.org/wiki/IPv6"&gt;IPv6&lt;/a&gt; very much not so,
partly because I don't have a clue about IPv6 (and let's be honest, network in
general), partly because it's an almost 30 years old pile of
designed-by-committee RFC.&lt;/p&gt;
&lt;p&gt;Amyway, the Freebox Pop is giving me seven &lt;code&gt;/64&lt;/code&gt; prefixes that I can &lt;a href="https://en.wikipedia.org/wiki/Prefix_delegation"&gt;freely
delegate&lt;/a&gt;, so for simplicity's
sake and because I'm a lazy punk, I:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;s&gt;waste&lt;/s&gt; use one for the network between the Freebox and the WAN
   interface of OPNSense.&lt;/li&gt;
&lt;li&gt;use a second one for the LAN&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;+──────────+
│ Internet │
+──────────+
     │
     ▼
┌─────────┐
│ Freebox │
└─────────┘
     │      prefix A
     ▼
┌──────────┐
│ OPNSense │
└──────────┘
     │      prefix B
     ▼
  +─────+
  │ LAN │
  +─────+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Apparently, it's possible to not waste a prefix for the network between the
Freebox and the router, but in the spirit of modern times, I'm comfortable
wasting a significant amount of resources because I couldn't be bothered.&lt;/p&gt;
&lt;h1&gt;Freebox side&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;http://mafreebox.freebox.fr&lt;/code&gt; in your browser&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Paramètres de la Freebox&lt;/code&gt; -&amp;gt; &lt;code&gt;Réseau Local: Mode Réseau&lt;/code&gt; -&amp;gt; &lt;code&gt;Bridge&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;http://mafreebox.freebox.fr&lt;/code&gt; in your browser&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Paramètres de la Freebox&lt;/code&gt; -&amp;gt; &lt;code&gt;Connexion Internet: Configuration IPv6&lt;/code&gt;&lt;ol&gt;
&lt;li&gt;Note the &lt;a href="https://en.wikipedia.org/wiki/Link-local_address"&gt;Local link address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Note the first and second delegate prefixes, eg. &lt;code&gt;2a01:xxx:xxx:xxx1::&lt;/code&gt;
   and &lt;code&gt;2a01:xxx:xxx:xxx2::&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disable the &lt;code&gt;IPv6 firewall&lt;/code&gt;, since it's dropping ~everything and can't
   be configured besides on/off.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;OPNSense side&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Open the admin interface&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Firewall&lt;/code&gt; -&amp;gt; &lt;code&gt;Settings&lt;/code&gt; -&amp;gt; &lt;code&gt;Advanced&lt;/code&gt; -&amp;gt; &lt;code&gt;Allow IPv6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Interfaces&lt;/code&gt; -&amp;gt; &lt;code&gt;Overview&lt;/code&gt; -&amp;gt; &lt;code&gt;WAN&lt;/code&gt; should contain an IPv6 starting with
   &lt;code&gt;fe80:&lt;/code&gt;: note it down. It's the Local link address of the WAN interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System&lt;/code&gt; -&amp;gt; &lt;code&gt;Gateway&lt;/code&gt; -&amp;gt; &lt;code&gt;Add&lt;/code&gt;:&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt;: FreeboxIPv6Gateway&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IP Address&lt;/code&gt;: IPv6 address of the Freebox in the first delegate prefix, &lt;code&gt;2a01:xxx:xxx:xxx1::1&lt;/code&gt; in our case&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Upstream gateway&lt;/code&gt;: tick the box&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Monitor IP&lt;/code&gt;: tick the box, if only to be warned/have logs &lt;s&gt;if&lt;/s&gt;
   when things go South&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Back to the Freebox side&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;http://mafreebox.freebox.fr/&lt;/code&gt; in your browser&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Paramètres de la Freebox&lt;/code&gt; -&amp;gt; &lt;code&gt;Connexion Internet: Configuration IPv6&lt;/code&gt; -&amp;gt;
   &lt;code&gt;Délégation de prefixe&lt;/code&gt;: add the &lt;em&gt;Local link address of the WAN interface&lt;/em&gt;
   into the &lt;code&gt;Next Hop&lt;/code&gt; field for the first and second prefixes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Back to the OPNSense side&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Interfaces&lt;/code&gt; -&amp;gt; &lt;code&gt;WAN&lt;/code&gt;:&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Generic configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;IPv6 Configuration Type&lt;/code&gt;, set it to &lt;code&gt;Static IPv6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Static IPv6 configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;IPv6 address&lt;/code&gt;, set it to any IPv6 address
   present in the first delegated prefix but the one ending in &lt;code&gt;:1&lt;/code&gt; since
   it's already used by the Freebox. I put &lt;code&gt;2a01:xxx:xxx:xxx1::2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPv6 Upstream Gateway&lt;/code&gt;: put the gateway we created, FreeboxIPv6Gateway.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Interfaces&lt;/code&gt; -&amp;gt; &lt;code&gt;LAN&lt;/code&gt;:&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Generic configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;IPv6 Configuration Type&lt;/code&gt;, set it to &lt;code&gt;Static IPv6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Static IPv6 configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;IPv6 address&lt;/code&gt;, set it to any IPv6 address
   present in the second delegated prefix but the one ending in &lt;code&gt;:1&lt;/code&gt; since
   it's already used by the Freebox. I put &lt;code&gt;2a01:xxx:xxx:xxx2::2&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And now comes the salt: in IPv4, one would normally use &lt;a href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol"&gt;DHCP&lt;/a&gt;
to assign IP addresses. In IPv6, one can use &lt;a href="https://en.wikipedia.org/wiki/DHCPv6"&gt;DHCPv6&lt;/a&gt;
or &lt;a href="https://en.wikipedia.org/wiki/IPv6#Stateless_address_autoconfiguration_(SLAAC).
The former [isn't supported by Android](https://issuetracker.google.com/issues/36949085) and looks horrible
while the latter used to be a privacy shitshow, but somehow devolved into a
[complexity one](https://www.internetsociety.org/resources/deploy360/2014/privacy-extensions-for-ipv6-slaac/)
where clients are generating their ipv6 on their own, and then ask their
neighbours if it's already used on the network via Duplicate Address
Detection. Of course, since SLAAC doesn't provide DNS information, one can
used both SLAAC and DHCPv6-in-stateless-mod"&gt;SLAAC+RDNSS&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Anyway, I'm going with SLAAC only and hoping for the best.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;code&gt;Services&lt;/code&gt; -&amp;gt; &lt;code&gt;Router advertisements&lt;/code&gt; -&amp;gt; &lt;code&gt;WAN&lt;/code&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Router Advertisements&lt;/code&gt; -&amp;gt; &lt;code&gt;Router Only&lt;/code&gt;, since I use a fixed IPv6 for
   the WAN interface of the router, and don't provide network access to
   anything else on this segment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Advertise Default Gateway&lt;/code&gt;, tick the box.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Services&lt;/code&gt; -&amp;gt; &lt;code&gt;Router advertisements&lt;/code&gt; -&amp;gt; &lt;code&gt;LAN&lt;/code&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Router Advertisements&lt;/code&gt; -&amp;gt; &lt;code&gt;Stateless&lt;/code&gt;, and pray&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Advertise Default Gateway&lt;/code&gt;, tick the box.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Adversitse Routes&lt;/code&gt;, put the second prefix.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another (mild) wave of saltiness: you need to punch holes into your firewall to
allow &lt;strong&gt;incoming traffic&lt;/strong&gt; for &lt;a href="https://en.wikipedia.org/wiki/ICMPv6"&gt;ICMPv6&lt;/a&gt;,
otherwise things might just break. Fear not, there is a &lt;a href="https://datatracker.ietf.org/doc/html/rfc4890"&gt;whole
RFC&lt;/a&gt; about what should normally
not be dropped, what will be dropped anyway, what a policy should be defined
for, and what should be dropped unless a good case can be made, both for
Transit Traffic and Local Configuration Traffic. At this point I just wanted
things to work, so I courageously just gave up and trusted OPNSense
"Automatically generated rules" to take care of this for me.&lt;/p&gt;
&lt;p&gt;Oh, and if you have things like Jellyfin, set the firewall to "conservative",
otherwise it'll randomly drop your websocket connections, and you'll
waste a whole afternoon debugging it.&lt;/p&gt;
&lt;!--
https://blog.vinishor.xyz/posts/mettre-en-place-ipv6-avec-une-freebox-et-opnsense.html
https://www.osnet.eu/en/node/752
https://lafibre.info/remplacer-freebox/tuto-freebox-pop-pfsense-ipv6-pop-player-oqee/
https://www.osnet.eu/fr/content/tutoriels/ipv6-sur-une-freebox-en-bridge-avec-opnsense-ou-pfsense
--&gt;</content><category term="sysadmin"></category></entry><entry><title>mat2 0.14.0</title><link href="https://dustri.org/b/mat2-0140.html" rel="alternate"></link><published>2025-10-23T15:30:00+02:00</published><updated>2025-10-23T15:30:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-10-23:/b/mat2-0140.html</id><summary type="html">&lt;p&gt;There is a new version of mat2:
&lt;a href="https://github.com/jvoisin/mat2/releases/tag/0.14.0"&gt;0.14.0&lt;/a&gt;, with a new feature and a
deprecation, to balance things out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add webp support&lt;/li&gt;
&lt;li&gt;Improve reliability&lt;/li&gt;
&lt;li&gt;Correctly handle PDF with weird filenames&lt;/li&gt;
&lt;li&gt;Improve epub support&lt;/li&gt;
&lt;li&gt;Improve MSOffice documents support&lt;/li&gt;
&lt;li&gt;Add Python 3.13 and 3.14 support&lt;/li&gt;
&lt;li&gt;Remove bubblewrap sandboxing …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;There is a new version of mat2:
&lt;a href="https://github.com/jvoisin/mat2/releases/tag/0.14.0"&gt;0.14.0&lt;/a&gt;, with a new feature and a
deprecation, to balance things out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add webp support&lt;/li&gt;
&lt;li&gt;Improve reliability&lt;/li&gt;
&lt;li&gt;Correctly handle PDF with weird filenames&lt;/li&gt;
&lt;li&gt;Improve epub support&lt;/li&gt;
&lt;li&gt;Improve MSOffice documents support&lt;/li&gt;
&lt;li&gt;Add Python 3.13 and 3.14 support&lt;/li&gt;
&lt;li&gt;Remove bubblewrap sandboxing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bubblewrap sandboxing was removed as it was a significant source of issues over
the years, was annoying to test in the continuous integration suite, didn't
provide significant security improvement besides mitigating possible command
injections in exiftool, and was best-effort anyway in the threat model.&lt;/p&gt;
&lt;p&gt;Another important change is that the main repository for mat2 moved from
&lt;a href="https://0xacab.org/jvoisin/mat2"&gt;0xacab&lt;/a&gt; to
&lt;a href="https://github.com/jvoisin/mat2"&gt;github&lt;/a&gt;, for multiple reasons. First, because
the web is a terrible place, 0xacab has to deal with abuses in various shapes
and forms, and the easiest way to mitigate it is to make it non-trivial to
register an account on the platform. Unfortunately, this makes it harder for
people to report issues, or to contribute to mat2. Second, running computers is
expensive, and I'd rather burn Microsoft's money than
&lt;a href="https://riseup.net"&gt;riseup&lt;/a&gt;'s one. Third, Gitlab is becoming bloated and
confusing, especially for such a small project as mat2. I'm not particularly
happy about the move, as I'd rather use/depend on non-profit owned/operated
infrastructure than an evil megacorp one, but it was a pragmatic decision.
Worse case, I moved it once, I can always move it somewhere else in the future
if needed.&lt;/p&gt;
&lt;p&gt;As usual, if you know some python help is
&lt;a href="https://github.com/jvoisin/mat2/issues"&gt;welcome&lt;/a&gt;.&lt;/p&gt;</content><category term="metadata"></category></entry><entry><title>Fixing "'humanize' is not a registered tag library" on postorious</title><link href="https://dustri.org/b/fixing-humanize-is-not-a-registered-tag-library-on-postorious.html" rel="alternate"></link><published>2025-10-23T14:00:00+02:00</published><updated>2025-10-23T14:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-10-23:/b/fixing-humanize-is-not-a-registered-tag-library-on-postorious.html</id><summary type="html">&lt;p&gt;At &lt;a href="https://nos-oignons.net/%C3%80_propos/index.en.html"&gt;Nos oignons&lt;/a&gt;, we're
running &lt;a href="https://nos-oignons.net/Services/index.en.html"&gt;Tor exit nodes&lt;/a&gt;, but
also a handful of services, like our website, some git repositories, some
lightweight monitoring, … but also internal and external mailing lists. For the
latter, we're using
&lt;a href="https://wiki.list.org/"&gt;mailman3&lt;/a&gt;/&lt;a href="https://wiki.list.org/HyperKitty"&gt;hyperkitty&lt;/a&gt;
with &lt;a href="https://schleuder.org/"&gt;schleuder&lt;/a&gt; on top of it, making it an unholy pile
of python …&lt;/p&gt;</summary><content type="html">&lt;p&gt;At &lt;a href="https://nos-oignons.net/%C3%80_propos/index.en.html"&gt;Nos oignons&lt;/a&gt;, we're
running &lt;a href="https://nos-oignons.net/Services/index.en.html"&gt;Tor exit nodes&lt;/a&gt;, but
also a handful of services, like our website, some git repositories, some
lightweight monitoring, … but also internal and external mailing lists. For the
latter, we're using
&lt;a href="https://wiki.list.org/"&gt;mailman3&lt;/a&gt;/&lt;a href="https://wiki.list.org/HyperKitty"&gt;hyperkitty&lt;/a&gt;
with &lt;a href="https://schleuder.org/"&gt;schleuder&lt;/a&gt; on top of it, making it an unholy pile
of python, ruby, gpg and email shenanigans that the sysadmin team has to
prevent from falling over.&lt;/p&gt;
&lt;p&gt;Unfortunately, teaching sand to think was a mistake, and anything running
on a computer will invariably fail at some point, mailing lists are no
exceptions. Today I got the following email on the &lt;code&gt;schleuder-admins@&lt;/code&gt; list:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;Net&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ReadTimeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;TCPSocket&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;229&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;rbuf_fill&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/3.3.0/net/protocol.rb:199:in `readuntil&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;209&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/gems/3.3.0/gems/net-smtp-0.5.1/lib/net/smtp.rb:1017:in `recv_response&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;979&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/gems/3.3.0/gems/net-smtp-0.5.1/lib/net/smtp.rb:1027:in `critical&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;965&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/gems/3.3.0/gems/net-smtp-0.5.1/lib/net/smtp.rb:799:in `block in send_message&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;926&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;rcptto_list&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/gems/3.3.0/gems/net-smtp-0.5.1/lib/net/smtp.rb:799:in `send_message&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;delivery_methods&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp_connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;deliver&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/mail/network/delivery_methods/smtp.rb:101:in `block in deliver!&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.3.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;643&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="k"&gt;start&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/mail/network/delivery_methods/smtp.rb:109:in `start_smtp_session&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;delivery_methods&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;deliver&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/mail/message.rb:2145:in `do_delivery&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;deliver&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/mail/gpg/delivery_handler.rb:27:in `deliver_mail&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;253&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;deliver&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/logger_notifications.rb:48:in `block in notify_admin&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;schleuder&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logger_notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="k"&gt;each&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/logger_notifications.rb:29:in `notify_admin&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;schleuder&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logger_notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/list.rb:379:in `rescue in block in send_to_subscriptions&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;schleuder&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;362&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send_to_subscriptions&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/share/rubygems-integration/all/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:98:in `each&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rubygems&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ow"&gt;all&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;activerecord&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;7.2.2.1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;active_record&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;delegation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="k"&gt;each&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/list.rb:361:in `send_to_subscriptions&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vendor_ruby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;schleuder&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/lib/ruby/vendor_ruby/schleuder/cli.rb:38:in `work&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rubygems&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ow"&gt;all&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;thor&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.3.2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;thor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/share/rubygems-integration/all/gems/thor-1.3.2/lib/thor/invocation.rb:127:in `invoke_command&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rubygems&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ow"&gt;all&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;thor&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.3.2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;thor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;538&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;/usr/share/rubygems-integration/all/gems/thor-1.3.2/lib/thor/base.rb:584:in `start&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;schleuder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;


&lt;span class="s1"&gt;[Django] ERROR (EXTERNAL IP): Internal Server Error:.eml&lt;/span&gt;
&lt;span class="s1"&gt;Subject: [Django] ERROR (EXTERNAL IP): Internal Server Error: /postorius/lists/&amp;lt;REDACTED&amp;gt;@nos-oignons.net/held_messages&lt;/span&gt;
&lt;span class="s1"&gt;From: &amp;lt;REDACTED&amp;gt;@lists.nos-oignons.net&lt;/span&gt;
&lt;span class="s1"&gt;Date: Thu, 23 Oct 2025 05:06:17 -0000&lt;/span&gt;
&lt;span class="s1"&gt;To: root@localhost, &amp;lt;REDACTED&amp;gt;@nos-oignons.net&lt;/span&gt;

&lt;span class="s1"&gt;Internal Server Error: /postorius/lists/&amp;lt;REDACTED&amp;gt;@nos-oignons.net/held_messages&lt;/span&gt;

&lt;span class="s1"&gt;TemplateSyntaxError at /postorius/lists/&amp;lt;REDACTED&amp;gt;@nos-oignons.net/held_messages&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; is not a registered tag library. Must be one of:&lt;/span&gt;
&lt;span class="s1"&gt;account&lt;/span&gt;
&lt;span class="s1"&gt;admin_list&lt;/span&gt;
&lt;span class="s1"&gt;admin_modify&lt;/span&gt;
&lt;span class="s1"&gt;admin_urls&lt;/span&gt;
&lt;span class="s1"&gt;allauth&lt;/span&gt;
&lt;span class="s1"&gt;bootstrap_tags&lt;/span&gt;
&lt;span class="s1"&gt;cache&lt;/span&gt;
&lt;span class="s1"&gt;compress&lt;/span&gt;
&lt;span class="s1"&gt;d_gravatar&lt;/span&gt;
&lt;span class="s1"&gt;date_helpers&lt;/span&gt;
&lt;span class="s1"&gt;debugger_tags&lt;/span&gt;
&lt;span class="s1"&gt;decorate&lt;/span&gt;
&lt;span class="s1"&gt;gravatar&lt;/span&gt;
&lt;span class="s1"&gt;highlight&lt;/span&gt;
&lt;span class="s1"&gt;highlighting&lt;/span&gt;
&lt;span class="s1"&gt;hk_generic&lt;/span&gt;
&lt;span class="s1"&gt;hk_haystack&lt;/span&gt;
&lt;span class="s1"&gt;i18n&lt;/span&gt;
&lt;span class="s1"&gt;indent_text&lt;/span&gt;
&lt;span class="s1"&gt;l10n&lt;/span&gt;
&lt;span class="s1"&gt;log&lt;/span&gt;
&lt;span class="s1"&gt;markdown&lt;/span&gt;
&lt;span class="s1"&gt;membership_helpers&lt;/span&gt;
&lt;span class="s1"&gt;more_like_this&lt;/span&gt;
&lt;span class="s1"&gt;nav_helpers&lt;/span&gt;
&lt;span class="s1"&gt;p_gravatar&lt;/span&gt;
&lt;span class="s1"&gt;pagination&lt;/span&gt;
&lt;span class="s1"&gt;postorius_helpers&lt;/span&gt;
&lt;span class="s1"&gt;rest_framework&lt;/span&gt;
&lt;span class="s1"&gt;socialaccount&lt;/span&gt;
&lt;span class="s1"&gt;static&lt;/span&gt;
&lt;span class="s1"&gt;syntax_color&lt;/span&gt;
&lt;span class="s1"&gt;tz&lt;/span&gt;
&lt;span class="s1"&gt;widont&lt;/span&gt;

&lt;span class="s1"&gt;Request Method: GET&lt;/span&gt;
&lt;span class="s1"&gt;Request URL: https://lists.nos-oignons.net/postorius/lists/&amp;lt;REDACTED&amp;gt;@nos-oignons.net/held_messages&lt;/span&gt;
&lt;span class="s1"&gt;Django Version: 4.2.23&lt;/span&gt;
&lt;span class="s1"&gt;Python Executable: /usr/bin/uwsgi-core&lt;/span&gt;
&lt;span class="s1"&gt;Python Version: 3.13.5&lt;/span&gt;
&lt;span class="s1"&gt;Python Path: [&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python313&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="mf"&gt;.13&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="mf"&gt;.13&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dynload&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="mf"&gt;.13&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;]&lt;/span&gt;
&lt;span class="s1"&gt;Server time: Thu, 23 Oct 2025 05:06:17 +0000&lt;/span&gt;
&lt;span class="s1"&gt;Installed Applications:&lt;/span&gt;
&lt;span class="s1"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;hyperkitty&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;postorius&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django_mailman3&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contenttypes&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;rest_framework&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django_gravatar&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;compressor&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django_extensions&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django_q&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;allauth&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;allauth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;allauth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socialaccount&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)&lt;/span&gt;
&lt;span class="s1"&gt;Installed Middleware:&lt;/span&gt;
&lt;span class="s1"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;allauth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccountMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommonMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CsrfViewMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocaleMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickjacking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XFrameOptionsMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django_mailman3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimezoneMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&lt;/span&gt;
&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;postorius&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostoriusMiddleware&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)&lt;/span&gt;


&lt;span class="s1"&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/defaulttags.py&amp;quot;, line 1026, in find_library&lt;/span&gt;
&lt;span class="s1"&gt;    return parser.libraries[name]&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;

&lt;span class="s1"&gt;During handling of the above exception (&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;), another exception occurred:&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/core/handlers/exception.py&amp;quot;, line 55, in inner&lt;/span&gt;
&lt;span class="s1"&gt;    response = get_response(request)&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/core/handlers/base.py&amp;quot;, line 197, in _get_response&lt;/span&gt;
&lt;span class="s1"&gt;    response = wrapped_callback(request, *callback_args, **callback_kwargs)&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/contrib/auth/decorators.py&amp;quot;, line 23, in _wrapper_view&lt;/span&gt;
&lt;span class="s1"&gt;    return view_func(request, *args, **kwargs)&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/postorius/auth/decorators.py&amp;quot;, line 66, in wrapper&lt;/span&gt;
&lt;span class="s1"&gt;    return fn(*args, **kwargs)&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/postorius/views/list.py&amp;quot;, line 889, in list_moderation&lt;/span&gt;
&lt;span class="s1"&gt;    return render(request, &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;postorius&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lists&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;held_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, context)&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/shortcuts.py&amp;quot;, line 24, in render&lt;/span&gt;
&lt;span class="s1"&gt;    content = loader.render_to_string(template_name, context, request, using=using)&lt;/span&gt;
&lt;span class="s1"&gt;              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/loader.py&amp;quot;, line 61, in render_to_string&lt;/span&gt;
&lt;span class="s1"&gt;    template = get_template(template_name, using=using)&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/loader.py&amp;quot;, line 15, in get_template&lt;/span&gt;
&lt;span class="s1"&gt;    return engine.get_template(template_name)&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/backends/django.py&amp;quot;, line 33, in get_template&lt;/span&gt;
&lt;span class="s1"&gt;    return Template(self.engine.get_template(template_name), self)&lt;/span&gt;
&lt;span class="s1"&gt;                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/engine.py&amp;quot;, line 175, in get_template&lt;/span&gt;
&lt;span class="s1"&gt;    template, origin = self.find_template(template_name)&lt;/span&gt;
&lt;span class="s1"&gt;                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/engine.py&amp;quot;, line 157, in find_template&lt;/span&gt;
&lt;span class="s1"&gt;    template = loader.get_template(name, skip=skip)&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/loaders/cached.py&amp;quot;, line 57, in get_template&lt;/span&gt;
&lt;span class="s1"&gt;    template = super().get_template(template_name, skip)&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/loaders/base.py&amp;quot;, line 28, in get_template&lt;/span&gt;
&lt;span class="s1"&gt;    return Template(&lt;/span&gt;

&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 154, in __init__&lt;/span&gt;
&lt;span class="s1"&gt;    self.nodelist = self.compile_nodelist()&lt;/span&gt;
&lt;span class="s1"&gt;                    ^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 200, in compile_nodelist&lt;/span&gt;
&lt;span class="s1"&gt;    return parser.parse()&lt;/span&gt;
&lt;span class="s1"&gt;           ^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 513, in parse&lt;/span&gt;
&lt;span class="s1"&gt;    raise self.error(token, e)&lt;/span&gt;
&lt;span class="s1"&gt;    ^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 511, in parse&lt;/span&gt;
&lt;span class="s1"&gt;    compiled_result = compile_func(self, token)&lt;/span&gt;
&lt;span class="s1"&gt;                      ^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/loader_tags.py&amp;quot;, line 293, in do_extends&lt;/span&gt;
&lt;span class="s1"&gt;    nodelist = parser.parse()&lt;/span&gt;
&lt;span class="s1"&gt;               ^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 513, in parse&lt;/span&gt;
&lt;span class="s1"&gt;    raise self.error(token, e)&lt;/span&gt;
&lt;span class="s1"&gt;    ^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/base.py&amp;quot;, line 511, in parse&lt;/span&gt;
&lt;span class="s1"&gt;    compiled_result = compile_func(self, token)&lt;/span&gt;
&lt;span class="s1"&gt;                      ^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/defaulttags.py&amp;quot;, line 1088, in load&lt;/span&gt;
&lt;span class="s1"&gt;    lib = find_library(parser, name)&lt;/span&gt;
&lt;span class="s1"&gt;          ^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class="s1"&gt;  File &amp;quot;/usr/lib/python3/dist-packages/django/template/defaulttags.py&amp;quot;, line 1028, in find_library&lt;/span&gt;
&lt;span class="s1"&gt;    raise TemplateSyntaxError(&lt;/span&gt;
&lt;span class="s1"&gt;    ^&lt;/span&gt;

&lt;span class="s1"&gt;Exception Type: TemplateSyntaxError at /postorius/lists/ag@nos-oignons.net/held_messages&lt;/span&gt;
&lt;span class="s1"&gt;Exception Value: &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;account&lt;/span&gt;
&lt;span class="n"&gt;admin_list&lt;/span&gt;
&lt;span class="n"&gt;admin_modify&lt;/span&gt;
&lt;span class="n"&gt;admin_urls&lt;/span&gt;
&lt;span class="n"&gt;allauth&lt;/span&gt;
&lt;span class="n"&gt;bootstrap_tags&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;
&lt;span class="nf"&gt;compress&lt;/span&gt;
&lt;span class="n"&gt;d_gravatar&lt;/span&gt;
&lt;span class="n"&gt;date_helpers&lt;/span&gt;
&lt;span class="n"&gt;debugger_tags&lt;/span&gt;
&lt;span class="n"&gt;decorate&lt;/span&gt;
&lt;span class="n"&gt;gravatar&lt;/span&gt;
&lt;span class="n"&gt;highlight&lt;/span&gt;
&lt;span class="n"&gt;highlighting&lt;/span&gt;
&lt;span class="n"&gt;hk_generic&lt;/span&gt;
&lt;span class="n"&gt;hk_haystack&lt;/span&gt;
&lt;span class="n"&gt;i18n&lt;/span&gt;
&lt;span class="n"&gt;indent_text&lt;/span&gt;
&lt;span class="n"&gt;l10n&lt;/span&gt;
&lt;span class="nf"&gt;log&lt;/span&gt;
&lt;span class="n"&gt;markdown&lt;/span&gt;
&lt;span class="n"&gt;membership_helpers&lt;/span&gt;
&lt;span class="n"&gt;more_like_this&lt;/span&gt;
&lt;span class="n"&gt;nav_helpers&lt;/span&gt;
&lt;span class="n"&gt;p_gravatar&lt;/span&gt;
&lt;span class="n"&gt;pagination&lt;/span&gt;
&lt;span class="n"&gt;postorius_helpers&lt;/span&gt;
&lt;span class="n"&gt;rest_framework&lt;/span&gt;
&lt;span class="n"&gt;socialaccount&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;
&lt;span class="n"&gt;syntax_color&lt;/span&gt;
&lt;span class="n"&gt;tz&lt;/span&gt;
&lt;span class="n"&gt;widont&lt;/span&gt;
&lt;span class="n"&gt;Raised&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;during&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;postorius&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_moderation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since this is a &lt;a href="https://www.djangoproject.com/"&gt;django&lt;/a&gt; stacktrace complaining
about a missing application, so it should simply be a matter of
adding to &lt;code&gt;/usr/share/mailman3-web/settings.py&lt;/code&gt;. Unfortunately:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;root@bulbe:~# &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;humanize&lt;span class="w"&gt; &lt;/span&gt;/usr/share/mailman3-web/settings.py
&lt;span class="go"&gt;    &amp;#39;django.contrib.humanize&amp;#39;,&lt;/span&gt;
&lt;span class="gp"&gt;root@bulbe:~#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After a fair amount of cursing, spelunking in &lt;a href="https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/"&gt;mailman-users
&lt;/a&gt; and
various &lt;code&gt;strace&lt;/code&gt;+&lt;code&gt;grep&lt;/code&gt; monstrosities, the
solution was found: Instead of adding &lt;code&gt;'django.contrib.humanize'&lt;/code&gt; to the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; tuple
in &lt;code&gt;/usr/share/mailman3-web/settings.py&lt;/code&gt; as one would expect, it should be
added in &lt;code&gt;/etc/mailman3/mailman-web.py&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;In the hope that this blogpost will help you waste less time on this than I
did.&lt;/p&gt;</content><category term="sysadmin"></category></entry><entry><title>Silencing a Kitchencook teatime kettle</title><link href="https://dustri.org/b/silencing-a-kitchencook-teatime-kettle.html" rel="alternate"></link><published>2025-10-13T18:00:00+02:00</published><updated>2025-10-13T18:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-10-13:/b/silencing-a-kitchencook-teatime-kettle.html</id><summary type="html">&lt;p&gt;My household recently acquired a &lt;a href="https://kitchencook.fr/bouilloire/643-bouilloire-electrique-2200w-modele-tea-time-kitchencook-3662738007507.html"&gt;Kitchencook
TEATIME&lt;/a&gt;
kettle. It's quite fancy, with a handful of features that I don't really use
nor care about, but I'm quite content with its 1.7L capacity.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle" src="https://dustri.org/b/images/kettle.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, it
beeps &lt;strong&gt;a lot&lt;/strong&gt;. Here is a non-exhaustive list of things resulting in a
dreadful unwanted …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My household recently acquired a &lt;a href="https://kitchencook.fr/bouilloire/643-bouilloire-electrique-2200w-modele-tea-time-kitchencook-3662738007507.html"&gt;Kitchencook
TEATIME&lt;/a&gt;
kettle. It's quite fancy, with a handful of features that I don't really use
nor care about, but I'm quite content with its 1.7L capacity.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle" src="https://dustri.org/b/images/kettle.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, it
beeps &lt;strong&gt;a lot&lt;/strong&gt;. Here is a non-exhaustive list of things resulting in a
dreadful unwanted noise: removing/putting the kettle from/on the base, when the
water is at the right temperature, when one turns it off/on, when one presses a
button, … sometimes even in the middle of the night for no apparent reason.
This is &lt;a href="https://dustri.org/b/objects-should-shut-the-fuck-up.html"&gt;fucking unacceptable behaviour&lt;/a&gt;, so here is
how to fix it. Start by doing yourself a service and get yourself a
&lt;a href="https://ifixit.com/en-eu/Tools/Drivers_and_Wrenches"&gt;screwdrivers kit from
iFixit&lt;/a&gt;, as Kitchencook
apparently hates their customers and decided to use &lt;a href="https://en.wikipedia.org/wiki/List_of_screw_drives#Tri-angle"&gt;Tri-angle
screws&lt;/a&gt; for the
base:&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle base" src="https://dustri.org/b/images/kettle_bottom.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Once open, remove the 3 &lt;a href="https://en.wikipedia.org/wiki/List_of_screw_drives#Phillips"&gt;phillips screws&lt;/a&gt;
fixing the PCB to the base:&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle pcb bottom" src="https://dustri.org/b/images/kettle_bottom_pcb.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The buzzer is the small cylindrical device on the bottom-left of the PCB:&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle pcb" src="https://dustri.org/b/images/kettle_pcb.jpg"&gt;&lt;/p&gt;
&lt;p&gt;It's a small &lt;a href="https://en.wikipedia.org/wiki/Piezoelectric_speaker"&gt;piezo&lt;/a&gt; from
ZFLY (Zhongshan Zhongli Electronics). The way piezoelectric speaker are working
is by having a small piece of &lt;a href="https://en.wikipedia.org/wiki/Piezoelectricity"&gt;piezoelectric
material&lt;/a&gt; fixed to a metallic
diaphragm, and to excite it via a small alternative voltage, so that the disc
will shrink/expand, causing the diaphragm to vibrate, and thus create sound.
Silencing the infernal machine is simply a matter of removing the diaphragm
altogether:&lt;/p&gt;
&lt;p&gt;&lt;img alt="kitchencook kettle buzzer" src="https://dustri.org/b/images/kettle_buzzer.jpg"&gt;
&lt;img alt="kitchencook kettle neutered buzzer" src="https://dustri.org/b/images/kettle_buzzer_neutered.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I'd recommend taping it to the plastic somewhere on the inside of the base, so
that you can always put if back should you part with the device, and hand it
over to some unhinged noise-lover maniac.&lt;/p&gt;
&lt;p&gt;You should now be able to enjoy your tea in a blissful silence.&lt;/p&gt;</content><category term="misc"></category></entry><entry><title>Snuffleupagus 0.12.0 - Stegodontidae</title><link href="https://dustri.org/b/snuffleupagus-0120-stegodontidae.html" rel="alternate"></link><published>2025-08-19T22:15:00+02:00</published><updated>2025-08-19T22:15:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-08-19:/b/snuffleupagus-0120-stegodontidae.html</id><summary type="html">&lt;p&gt;&lt;a href="https://snuffleupagus.readthedocs.org"&gt;&lt;img alt="snuffleupagus logo" src="https://dustri.org/b/images/sp.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I just published a new release of
&lt;a href="https://github.com/jvoisin/snuffleupagus/releases/tag/v0.12.0"&gt;Snuffleupagus&lt;/a&gt;,
the hardening module for php7+ and php8+,
version &lt;code&gt;0.12.0&lt;/code&gt;, codename "Stegodontidae",
named after the &lt;a href="https://en.wikipedia.org/wiki/Stegodontidae"&gt;extinct family of proboscideans&lt;/a&gt;,
a cousin of the elephants we know (and love.)
There aren't any new flashing features, only bug fixes and minor improvements,
along …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://snuffleupagus.readthedocs.org"&gt;&lt;img alt="snuffleupagus logo" src="https://dustri.org/b/images/sp.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I just published a new release of
&lt;a href="https://github.com/jvoisin/snuffleupagus/releases/tag/v0.12.0"&gt;Snuffleupagus&lt;/a&gt;,
the hardening module for php7+ and php8+,
version &lt;code&gt;0.12.0&lt;/code&gt;, codename "Stegodontidae",
named after the &lt;a href="https://en.wikipedia.org/wiki/Stegodontidae"&gt;extinct family of proboscideans&lt;/a&gt;,
a cousin of the elephants we know (and love.)
There aren't any new flashing features, only bug fixes and minor improvements,
along with the usual support of newer PHP versions.&lt;/p&gt;
&lt;h3&gt;Changelog&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Unify the default rules across all php versions&lt;/li&gt;
&lt;li&gt;Snuffleupagus will no longer report outdated PHP versions&lt;/li&gt;
&lt;li&gt;Fix a possible cookie-related crash&lt;/li&gt;
&lt;li&gt;Fix a NULL-pointer dereference&lt;/li&gt;
&lt;li&gt;Fix a minor portability issue&lt;/li&gt;
&lt;li&gt;Improve modern Debian support&lt;/li&gt;
&lt;li&gt;Improved documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As usual, if you want to help, we have some
&lt;a href="https://github.com/jvoisin/snuffleupagus/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22"&gt;low hanging fruits&lt;/a&gt; ♥&lt;/p&gt;
&lt;p&gt;See you in your PHP stack!&lt;/p&gt;</content><category term="php"></category></entry><entry><title>Manually fixing apt's "Unmet dependencies" error</title><link href="https://dustri.org/b/manually-fixing-apts-unmet-dependencies-error.html" rel="alternate"></link><published>2025-08-05T22:00:00+02:00</published><updated>2025-08-05T22:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-08-05:/b/manually-fixing-apts-unmet-dependencies-error.html</id><summary type="html">&lt;p&gt;I am, despite my best judgment and common sense, acting as a system
administrator for a handful of projects/users, sometimes on my own, sometimes
as part of a team. On the bright side, it's usually a great source of weird
debugging/workaround stories, like this one.&lt;/p&gt;
&lt;p&gt;With the &lt;a href="https://www.proxmox.com/en/about/company-details/press-releases/proxmox-virtual-environment-9-0"&gt;new …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I am, despite my best judgment and common sense, acting as a system
administrator for a handful of projects/users, sometimes on my own, sometimes
as part of a team. On the bright side, it's usually a great source of weird
debugging/workaround stories, like this one.&lt;/p&gt;
&lt;p&gt;With the &lt;a href="https://www.proxmox.com/en/about/company-details/press-releases/proxmox-virtual-environment-9-0"&gt;new release of
proxmox&lt;/a&gt;
and with 30 minutes of free time, a sysadmin team I'm part of thought it would
be nice to upgrade a box together. An admin ran &lt;code&gt;pve8to9 --full&lt;/code&gt;, changed the
repositories from bookworm to trixie, and ran &lt;code&gt;apt dist-upgrade&lt;/code&gt;, and… their
screen was filled with &lt;code&gt;WARNING: ld.so: invalid GLIBC_TUNABLES
`glibc.malloc.perturb=1,glibc.malloc.check=1,glibc.malloc.tcache_count=0':
ignored.&lt;/code&gt;. Panic. So they hit &lt;code&gt;&amp;lt;C-c&amp;gt;&lt;/code&gt; to investigate what was happening.
Turns out, another admin threw those configuration options somewhere to
"harden" the glibc allocator, and they're now deprecated, hence the message. No
big deal, this can be fixed by removing those options, and running &lt;code&gt;apt
dist-upgrade&lt;/code&gt; again. Or can it?&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;# &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;dist-upgrade&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="go"&gt;Reading package lists... Done&lt;/span&gt;
&lt;span class="go"&gt;Building dependency tree... Done&lt;/span&gt;
&lt;span class="go"&gt;Reading state information... Done&lt;/span&gt;
&lt;span class="go"&gt;You might want to run &amp;#39;apt --fix-broken install&amp;#39; to correct these.&lt;/span&gt;
&lt;span class="go"&gt;The following packages have unmet dependencies:&lt;/span&gt;
&lt;span class="go"&gt; libanyevent-perl : Depends: perlapi-5.40.0&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libasync-interrupt-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libev-perl but it is not installed or&lt;/span&gt;
&lt;span class="go"&gt;                                libevent-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libguard-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libcommon-sense-perl : Depends: perl (&amp;lt; 5.36.1~) but 5.40.1-6 is installed&lt;/span&gt;
&lt;span class="go"&gt; libnss-systemd : Depends: systemd (= 257.7-1) but 252.38-1~deb12u1 is installed&lt;/span&gt;
&lt;span class="go"&gt; libpam-systemd : Depends: systemd (= 257.7-1) but 252.38-1~deb12u1 is installed&lt;/span&gt;
&lt;span class="go"&gt; libsasl2-2 : Depends: libssl3t64 (&amp;gt;= 3.0.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;              Recommends: libsasl2-modules (&amp;gt;= 2.1.28+dfsg1-9) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libsasl2-modules-db : Depends: libdb5.3t64 but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libsystemd-shared : Depends: libssl3t64 (&amp;gt;= 3.4.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; openssl : Depends: libssl3t64 (&amp;gt;= 3.5.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; perl : Depends: perl-base (= 5.40.1-6) but 5.36.0-7+deb12u2 is installed&lt;/span&gt;
&lt;span class="go"&gt;        Depends: libperl5.40 (= 5.40.1-6) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; perl-modules-5.40 : Depends: perl-base (&amp;gt;= 5.40.1-1) but 5.36.0-7+deb12u2 is installed&lt;/span&gt;
&lt;span class="go"&gt; systemd : Depends: libsystemd-shared (= 252.38-1~deb12u1) but 257.7-1 is installed&lt;/span&gt;
&lt;span class="go"&gt;           Depends: libsystemd0 (= 252.38-1~deb12u1) but 257.7-1 is installed&lt;/span&gt;
&lt;span class="go"&gt;E: Unmet dependencies. Try &amp;#39;apt --fix-broken install&amp;#39; with no packages (or specify a solution).&lt;/span&gt;
&lt;span class="go"&gt;[100]&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Alright, let's try &lt;code&gt;apt --fix-broken install&lt;/code&gt;:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;# &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;--fix-broken&lt;span class="w"&gt; &lt;/span&gt;install
&lt;span class="go"&gt;Reading package lists... Done&lt;/span&gt;
&lt;span class="go"&gt;Building dependency tree... Done&lt;/span&gt;
&lt;span class="go"&gt;Reading state information... Done&lt;/span&gt;
&lt;span class="go"&gt;Correcting dependencies... Done&lt;/span&gt;
&lt;span class="go"&gt;The following packages were automatically installed and are no longer required:&lt;/span&gt;

&lt;span class="go"&gt;[…]&lt;/span&gt;

&lt;span class="go"&gt;75 upgraded, 64 newly installed, 50 to remove and 530 not upgraded.&lt;/span&gt;
&lt;span class="go"&gt;17 not fully installed or removed.&lt;/span&gt;
&lt;span class="go"&gt;Need to get 0 B/118 MB of archives.&lt;/span&gt;
&lt;span class="go"&gt;After this operation, 215 MB of additional disk space will be used.&lt;/span&gt;
&lt;span class="go"&gt;Do you want to continue? [Y/n] y&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) !! WARNING !!&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) You are attempting to remove the meta-package &amp;#39;proxmox-ve&amp;#39;!&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) &lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) If you really want to permanently remove &amp;#39;proxmox-ve&amp;#39; from your system, run the following command&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook)   touch &amp;#39;/please-remove-proxmox-ve&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) run apt purge proxmox-ve to remove the meta-package&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) and repeat your apt invocation.&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) &lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook) If you are unsure why &amp;#39;proxmox-ve&amp;#39; would be removed, please verify&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook)   - your APT repository settings&lt;/span&gt;
&lt;span class="go"&gt;W: (pve-apt-hook)   - that you are using &amp;#39;apt full-upgrade&amp;#39; to upgrade your system&lt;/span&gt;
&lt;span class="go"&gt;E: Sub-process /usr/share/proxmox-ve/pve-apt-hook returned an error code (1)&lt;/span&gt;
&lt;span class="go"&gt;E: Failure running script /usr/share/proxmox-ve/pve-apt-hook&lt;/span&gt;
&lt;span class="go"&gt;[100]&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We're absolutely not going to do that, so let's use &lt;code&gt;apt-mark&lt;/code&gt; to tell &lt;code&gt;apt&lt;/code&gt;
to leave &lt;code&gt;proxmox-ve&lt;/code&gt; alone, and try the whole manoeuvre again:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;# &lt;/span&gt;apt-mark&lt;span class="w"&gt; &lt;/span&gt;hold&lt;span class="w"&gt; &lt;/span&gt;proxmox-ve
&lt;span class="go"&gt;proxmox-ve set on hold.&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;--fix-broken&lt;span class="w"&gt; &lt;/span&gt;install
&lt;span class="go"&gt;Reading package lists... Done&lt;/span&gt;
&lt;span class="go"&gt;Building dependency tree... Done&lt;/span&gt;
&lt;span class="go"&gt;Reading state information... Done&lt;/span&gt;
&lt;span class="go"&gt;Correcting dependencies... failed.&lt;/span&gt;
&lt;span class="go"&gt;The following packages have unmet dependencies:&lt;/span&gt;
&lt;span class="go"&gt; libanyevent-perl : Depends: perlapi-5.40.0&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libasync-interrupt-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libev-perl but it is not installed or&lt;/span&gt;
&lt;span class="go"&gt;                                libevent-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;                    Recommends: libguard-perl but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libcommon-sense-perl : Depends: perl (&amp;lt; 5.36.1~) but 5.40.1-6 is installed&lt;/span&gt;
&lt;span class="go"&gt; libnss-systemd : Depends: systemd (= 257.7-1) but 252.38-1~deb12u1 is installed&lt;/span&gt;
&lt;span class="go"&gt; libpam-systemd : Depends: systemd (= 257.7-1) but 252.38-1~deb12u1 is installed&lt;/span&gt;
&lt;span class="go"&gt; libsasl2-2 : Depends: libssl3t64 (&amp;gt;= 3.0.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt;              Recommends: libsasl2-modules (&amp;gt;= 2.1.28+dfsg1-9) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libsasl2-modules-db : Depends: libdb5.3t64 but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; libsystemd-shared : Depends: libssl3t64 (&amp;gt;= 3.4.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; openssl : Depends: libssl3t64 (&amp;gt;= 3.5.0) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; perl : Depends: perl-base (= 5.40.1-6) but 5.36.0-7+deb12u2 is installed&lt;/span&gt;
&lt;span class="go"&gt;        Depends: libperl5.40 (= 5.40.1-6) but it is not installed&lt;/span&gt;
&lt;span class="go"&gt; perl-modules-5.40 : Depends: perl-base (&amp;gt;= 5.40.1-1) but 5.36.0-7+deb12u2 is installed&lt;/span&gt;
&lt;span class="go"&gt; systemd : Depends: libsystemd-shared (= 252.38-1~deb12u1) but 257.7-1 is installed&lt;/span&gt;
&lt;span class="go"&gt;           Depends: libsystemd0 (= 252.38-1~deb12u1) but 257.7-1 is installed&lt;/span&gt;
&lt;span class="go"&gt;E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.&lt;/span&gt;
&lt;span class="go"&gt;E: Unable to correct dependencies&lt;/span&gt;
&lt;span class="go"&gt;[100]&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You might think that using &lt;code&gt;apt-mark hold&lt;/code&gt; for all the packages with unmet
dependencies is the way to go, but you would be wrong, as it doesn't fix shit.
You can check &lt;code&gt;apt&lt;/code&gt;'s documentation and ask the collective hivemind of the
internet, but we didn't find anything to solve our problem. Then we realised
that &lt;code&gt;apt&lt;/code&gt; has a graph of all packages and their dependencies stored somewhere
on the filesystem, and we found it via &lt;code&gt;strace -f -e openat 2&amp;gt;&amp;amp;1 apt install
--fix-missing | grep -oP "\"(.*)\"" | sort | uniq -c&lt;/code&gt;: it's &lt;code&gt;/var/lib/dpkg/status&lt;/code&gt;.
We can now edit it to remove the &lt;code&gt;Depends:&lt;/code&gt; field of every package with broken
dependencies to appease &lt;code&gt;apt&lt;/code&gt;'s dependencies solver via this big fat lie. Once done:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;# &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;upgrade
&lt;span class="go"&gt;Reading package lists... Done&lt;/span&gt;
&lt;span class="go"&gt;Building dependency tree... Done&lt;/span&gt;
&lt;span class="go"&gt;Reading state information... Done&lt;/span&gt;
&lt;span class="go"&gt;Calculating upgrade... Done&lt;/span&gt;
&lt;span class="go"&gt;The following packages were automatically installed and are no longer required:&lt;/span&gt;

&lt;span class="go"&gt;[…]&lt;/span&gt;

&lt;span class="go"&gt;Setting up ca-certificates (20250419) ...&lt;/span&gt;
&lt;span class="go"&gt;Updating certificates in /etc/ssl/certs...&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.3.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.5.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;dpkg: error processing package ca-certificates (--configure):&lt;/span&gt;
&lt;span class="go"&gt; installed ca-certificates package post-installation script subprocess returned error exit status 1&lt;/span&gt;
&lt;span class="go"&gt;Setting up busybox (1:1.37.0-6+b3) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libklibc:amd64 (2.0.14-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up novnc-pve (1.6.0-3) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libz3-4:amd64 (4.13.3-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up xz-utils (5.8.1-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libfribidi0:amd64 (1.0.16-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libopus0:amd64 (1.5.2-2) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libquadmath0:amd64 (14.2.0-19) ...&lt;/span&gt;
&lt;span class="go"&gt;dpkg: dependency problems prevent configuration of python3-requests:&lt;/span&gt;
&lt;span class="go"&gt; python3-requests depends on python3-certifi; however:&lt;/span&gt;
&lt;span class="go"&gt;  Package python3-certifi is not configured yet.&lt;/span&gt;
&lt;span class="go"&gt; python3-requests depends on ca-certificates; however:&lt;/span&gt;
&lt;span class="go"&gt;  Package ca-certificates is not configured yet.&lt;/span&gt;

&lt;span class="go"&gt;dpkg: error processing package python3-requests (--configure):&lt;/span&gt;
&lt;span class="go"&gt; dependency problems - leaving unconfigured&lt;/span&gt;
&lt;span class="go"&gt;Setting up libproc2-0:amd64 (2:4.0.4-9) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up proxmox-backup-restore-image (1.0.0) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up ssl-cert (1.1.3) ...&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.3.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.5.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;Signature algorithm of /etc/ssl/certs/ssl-cert-snakeoil.pem is not sha256. Recreating.&lt;/span&gt;
&lt;span class="go"&gt;Could not create certificate. Openssl output was:&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libssl.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.3.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.5.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.4.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;openssl: /lib/x86_64-linux-gnu/libcrypto.so.3: version `OPENSSL_3.2.0&amp;#39; not found (required by openssl)&lt;/span&gt;
&lt;span class="go"&gt;dpkg: error processing package ssl-cert (--configure):&lt;/span&gt;
&lt;span class="go"&gt; installed ssl-cert package post-installation script subprocess returned error exit status 1&lt;/span&gt;
&lt;span class="go"&gt;Setting up libxcb-sync1:amd64 (1.17.0-2+b1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up dtach (0.9-7) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up lsb-release (12.1-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up dbus-system-bus-common (1.16.2-2) ...&lt;/span&gt;
&lt;span class="go"&gt;systemd-sysusers: error while loading shared libraries: libsystemd-shared-252.so: cannot open shared object file: No such file or directory&lt;/span&gt;
&lt;span class="go"&gt;dpkg: error processing package dbus-system-bus-common (--configure):&lt;/span&gt;
&lt;span class="go"&gt; installed dbus-system-bus-common package post-installation script subprocess returned error exit status 127&lt;/span&gt;
&lt;span class="go"&gt;Setting up libconfuse2:amd64 (3.3-4) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libisl23:amd64 (0.27-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libcpg4:amd64 (3.1.9-pve2) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libcmap4:amd64 (3.1.9-pve2) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up libpulse0:amd64 (17.0+dfsg1-2+b1) ...&lt;/span&gt;
&lt;span class="go"&gt;dpkg: dependency problems prevent configuration of python3-pip-whl:&lt;/span&gt;
&lt;span class="go"&gt; python3-pip-whl depends on ca-certificates; however:&lt;/span&gt;
&lt;span class="go"&gt;  Package ca-certificates is not configured yet.&lt;/span&gt;

&lt;span class="go"&gt;dpkg: error processing package python3-pip-whl (--configure):&lt;/span&gt;
&lt;span class="go"&gt; dependency problems - leaving unconfigured&lt;/span&gt;
&lt;span class="go"&gt;Setting up libquorum5:amd64 (3.1.9-pve2) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up iptables (1.8.11-2) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up fontconfig-config (2.15.0-2.3) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up uidmap (1:4.17.4-2) ...&lt;/span&gt;
&lt;span class="go"&gt;dpkg: dependency problems prevent configuration of cron:&lt;/span&gt;
&lt;span class="go"&gt; cron depends on cron-daemon-common; however:&lt;/span&gt;
&lt;span class="go"&gt;  Package cron-daemon-common is not configured yet.&lt;/span&gt;

&lt;span class="go"&gt;dpkg: error processing package cron (--configure):&lt;/span&gt;
&lt;span class="go"&gt; dependency problems - leaving unconfigured&lt;/span&gt;
&lt;span class="go"&gt;Setting up python3-typeguard (4.4.2-1) ...&lt;/span&gt;
&lt;span class="go"&gt;Setting up rsyslog (8.2504.0-1) ...&lt;/span&gt;

&lt;span class="go"&gt;[…]&lt;/span&gt;


&lt;span class="go"&gt;dpkg: error processing package pve-manager (--configure):&lt;/span&gt;
&lt;span class="go"&gt; dependency problems - leaving triggers unprocessed&lt;/span&gt;
&lt;span class="go"&gt;Processing triggers for man-db (2.11.2-2) ...&lt;/span&gt;
&lt;span class="go"&gt;Processing triggers for sgml-base (1.31+nmu1) ...&lt;/span&gt;
&lt;span class="go"&gt;Errors were encountered while processing:&lt;/span&gt;
&lt;span class="go"&gt; ca-certificates&lt;/span&gt;
&lt;span class="go"&gt; python3-certifi&lt;/span&gt;
&lt;span class="go"&gt; ssl-cert&lt;/span&gt;
&lt;span class="go"&gt; python3-requests&lt;/span&gt;
&lt;span class="go"&gt; dbus-system-bus-common&lt;/span&gt;
&lt;span class="go"&gt; cron-daemon-common&lt;/span&gt;
&lt;span class="go"&gt; liblwp-protocol-https-perl&lt;/span&gt;
&lt;span class="go"&gt; libwww-perl&lt;/span&gt;
&lt;span class="go"&gt; python3-pip-whl&lt;/span&gt;
&lt;span class="go"&gt; cron&lt;/span&gt;
&lt;span class="go"&gt; libpve-common-perl&lt;/span&gt;
&lt;span class="go"&gt; libproxmox-acme-perl&lt;/span&gt;
&lt;span class="go"&gt; python3-pyvmomi&lt;/span&gt;
&lt;span class="go"&gt; libpve-apiclient-perl&lt;/span&gt;
&lt;span class="go"&gt; dbus&lt;/span&gt;
&lt;span class="go"&gt; libpve-guest-common-perl&lt;/span&gt;
&lt;span class="go"&gt; libpve-storage-perl&lt;/span&gt;
&lt;span class="go"&gt; libpve-access-control&lt;/span&gt;
&lt;span class="go"&gt; libpve-cluster-perl&lt;/span&gt;
&lt;span class="go"&gt; libpve-http-server-perl&lt;/span&gt;
&lt;span class="go"&gt; pve-ha-manager&lt;/span&gt;
&lt;span class="go"&gt; libpve-cluster-api-perl&lt;/span&gt;
&lt;span class="go"&gt; libpve-notify-perl&lt;/span&gt;
&lt;span class="go"&gt; pve-manager&lt;/span&gt;
&lt;span class="go"&gt;E: Sub-process /usr/bin/dpkg returned an error code (1)&lt;/span&gt;
&lt;span class="go"&gt;[100]&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Things are still broken, but less so, at least &lt;code&gt;apt&lt;/code&gt; is able to
upgrade/install/manage/… packages. Now it's simply a matter of running &lt;code&gt;dpkg
--force-all --configure -a&lt;/code&gt;, &lt;code&gt;apt-get install --fix-missing&lt;/code&gt; and &lt;code&gt;apt install
&amp;lt;PACKAGE&amp;gt;&lt;/code&gt; (with &lt;code&gt;&amp;lt;PACKAGE&amp;gt;&lt;/code&gt; being things listed in the &lt;code&gt;Errors were
encountered while processing:&lt;/code&gt; errors from the other commands) until you get no
more errors. At this point, you can reopen &lt;code&gt;/var/lib/dpkg/status&lt;/code&gt;, uncomment
the lines you commented if they're still present, and resume your &lt;code&gt;apt
dist-upgrade&lt;/code&gt;. Still, it's sad that in 2025 a package manager is a simple
&lt;code&gt;SIGINT&lt;/code&gt; away from being completely broken.&lt;/p&gt;</content><category term="sysadmin"></category></entry><entry><title>Objects should shut the fuck up</title><link href="https://dustri.org/b/objects-should-shut-the-fuck-up.html" rel="alternate"></link><published>2025-07-29T21:15:00+02:00</published><updated>2025-07-29T21:15:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-07-29:/b/objects-should-shut-the-fuck-up.html</id><summary type="html">&lt;p&gt;I have a small car, and it has a dual-tank: gas and
&lt;a href="https://en.wikipedia.org/wiki/Liquefied_petroleum_gas"&gt;LPG&lt;/a&gt;, which is a great
way to reduce my car-related budget, as LPG is way cheaper. Unfortunately, when
the tank is starting to get depleted, the car will emit strident and loud beeps
to notify me about it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have a small car, and it has a dual-tank: gas and
&lt;a href="https://en.wikipedia.org/wiki/Liquefied_petroleum_gas"&gt;LPG&lt;/a&gt;, which is a great
way to reduce my car-related budget, as LPG is way cheaper. Unfortunately, when
the tank is starting to get depleted, the car will emit strident and loud beeps
to notify me about it. And every single time time, it startles me like Hell,
which isn't something I appreciate very much, especially when I'm steering a 1
ton metal box to overtake a trailer at &lt;a href="https://en.wikipedia.org/wiki/Autoroutes_of_France#Motorway_speed_limits"&gt;130km/h on the
highway&lt;/a&gt;.
To make things even double-plus-good, a full-screen "LPG tank almost depleted!"
message will cover the whole dashboard. The very same dashboard that constantly
have at its bottom the current level of said LPG tank.&lt;/p&gt;
&lt;p&gt;The only time I want my car to maybe make some noise is when some critical shit
is happening, like the oil level decreasing at an alarming rate. Having it yell
at me that I'm only able to drive around 100 more kilometers on LPG, while I
have a &lt;strong&gt;full gasoline tank&lt;/strong&gt; affording me a total autonomy of like 1000
kilometres is anything but. I hate this, I hate that it's not configurable, I
hate that it's waking everyone asleep in the car (especially toddlers), and I
fucking hate that my car is actively lowering the safety of its passengers by
scaring its driver. And of course, the notification will repeat a couple of
times, at seemingly random intervals, likely because the complete bellend who
designed this terrible scheme is taking the ever-lowering worldwide car-crash
statistics as a personal affront, and is on a mission from God to fix this.&lt;/p&gt;
&lt;p&gt;This major papercut made me think about how making noise for anything but the
direst emergency should be an off-by-default privilege that only the user can
explicitly grant, instead if being the default for all electricity-powered
objects. I'm a CyberSecurity Professional™, earning a living breaking into
computer and computer-adjacent systems, so I own the bare minimum in terms of
Smart Devices™, and yet, yet I realised that I still have a non-zero amount of
infernal noise-making crap.&lt;/p&gt;
&lt;p&gt;For example, my washing machine has an obnoxious alarm when it completes a
cycle, that can fortunately be disabled via a (hidden!) menu. Now, I get it, it
might be useful to have some kind of alarm so that you don't forget your
soaking clothes and have them rot into a new variant of whatever medieval
disease. But, the alarm, while exceedingly loud, only lasts a handful of
seconds, making it close to useless. Moreover, if you forget your laundry long
enough for it to decay, you kind of deserve to have a Nurgle cult growing in
your basement. Even assuming for the sake of the argument that this
anti-feature could somehow be useful, this isn't the only yapping caused of
this fiendish machine: the fucking "beep" happening every time one turns the
knob or presses a button can't be deactivated. And don't you fucking dare talk
to me about accessibility: all buttons are touch-sensitive, so useless to
visual-impaired users, and all tones are exactly the same, making them
absolutely useless for anything but waking up/startling the sleeping and
unsuspecting house inhabitants. But this isn't everything, of course there is
more: it has a "cute" tone when it starts, for no fucking reason at all. Why is
this a thing? Who the fuck thought it would be a good idea? What's the
reasoning behind this? It's a washing machine, there is no complicated fragile
boot sequence, no hazardous warm-up shenanigans: I press the power-on button,
it starts. Imagine having this ludicrous behaviour on all your objects: Opening
your faucet? "DUDUDUDUUUUUUUU!" Unlocking your front-door?
"LULULUUUUULULUUUUUU!" Turning on the cooktop hood?
"LALALAAAAAAALAAAAAALAAAAA!" Maybe turning your lights on in your living room?
The Ride of the Valkyries starts blasting at full volume.&lt;/p&gt;
&lt;p&gt;As electricity is green-ish and cheap-ish where I'm living, I have the luxury
of having a drier as well, forming an unholy honky duo with the washing
machine: while it thankfully doesn't have a startup sound, the interaction-beep
can't be disabled there as well, nor can the alarm. You know, the alarm telling
me that my clothes are dry… There is no reasons, let alone urgency, that I
should get any form of audio notification about this. I could spent 6 months in
the hospital after a car crash because of the aforementioned LPG &lt;a href="https://en.wikipedia.org/wiki/Seven_trumpets"&gt;seven
trumpets&lt;/a&gt;, come back to my place,
and find my cloths still impeccably dry.&lt;/p&gt;
&lt;p&gt;The kitchen isn't spared either: my hotplates will try their very best to make
everyone deaf should something like a dishcloth, or perish the though, some
water be present on more than two touch-sensitive buttons at once. I fail to
conceptualize what the issue is here, and why this warrants all this racket:
doing nothing would be perfectly acceptable. Heck, if something really has to
be done for whatever regulation bullshit or whatnot, how about blinking the
lights used to convey that the plates are hot? Or, if you really need to take
action, just turn them off automatically. Really, anything but something that
would shame a car alarm in every way.&lt;/p&gt;
&lt;p&gt;But the very best, my complete favourite, "the world class, maybe even the
world champion" (kudos if you know where this is coming from), is a fucking
baby-phone that beeps when you turn it on. The use-case is "monitoring a
sleeping child", and the loud beep tends to wake the aforementioned kid up. May
the gormless cock-up who created this absolute potato of a device spend his
entire life walking on legos.&lt;/p&gt;
&lt;p&gt;Fortunately, everything isn't complete garbage in this world, and I even have a
couple of examples at hand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My dishwasher: no sound whatsoever, it simply opens up when it's done.&lt;/li&gt;
&lt;li&gt;My fridge: should I improperly close its door, it'll emit some faint noise
  for like 30 seconds. It's a totally valid important notification, as nobody
      wants to burn electricity to cold the room while the food goes bad.&lt;/li&gt;
&lt;li&gt;My ebook reader: it's physically unable to produce any sound.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The world is dire enough as it is without having me adding to my shopping
criteria "does it shut the fuck up?" to an already long list. If you're
designing objects, please take some time to test their notification mechanism
near an asleep toddler and/or a sleep-deprived lunatic, instead of making
piling more noisy interruptions to our already notification-saturated reality.&lt;/p&gt;</content><category term="rant"></category></entry><entry><title>Why is log(i^i) + pi/2 = 0?</title><link href="https://dustri.org/b/why-is-logii-pi2-0.html" rel="alternate"></link><published>2025-07-11T15:45:00+02:00</published><updated>2025-07-11T15:45:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-07-11:/b/why-is-logii-pi2-0.html</id><summary type="html">&lt;script defer src="./files/katex.min.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;p&gt;&lt;link rel="stylesheet" href="./files/katex.min.css"&gt;&lt;/p&gt;
&lt;script defer src="./files/auto-render.min.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script defer src="./files/katex_config.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;noscript&gt;
This article uses the (amazing) [KaTeX]( https://github.com/Khan/KaTeX )
javascript framework. It seems that you've disabled javascript,
so you won't have a sexy display of the equations, but since they're written
in LaTeX, I'm quite sure that you can figure how to render them locally
in a proper …&lt;/noscript&gt;</summary><content type="html">&lt;script defer src="./files/katex.min.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;p&gt;&lt;link rel="stylesheet" href="./files/katex.min.css"&gt;&lt;/p&gt;
&lt;script defer src="./files/auto-render.min.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script defer src="./files/katex_config.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;noscript&gt;
This article uses the (amazing) [KaTeX]( https://github.com/Khan/KaTeX )
javascript framework. It seems that you've disabled javascript,
so you won't have a sexy display of the equations, but since they're written
in LaTeX, I'm quite sure that you can figure how to render them locally
in a proper way ;)
&lt;/noscript&gt;

&lt;p&gt;I was watching &lt;a href="https://en.wikipedia.org/wiki/Lennart_Augustsson"&gt;Lennart
Augustsson&lt;/a&gt;'s &lt;a href="https://www.youtube.com/watch?v=SJwvPEq4Mok"&gt;MicroHs, a
tiny Haskell Compiler&lt;/a&gt; talk,
and saw that he mentioned a pretty neat equality: $$log(i^i) + \frac{\pi}{2} = 0$$,
and punctued it with a casual "it's obvious if you think about it." And even
though I dislike trigonometry and complex numbers, it's indeed pretty trivial,
thanks to &lt;a href="https://en.wikipedia.org/wiki/Euler%27s_identity"&gt;Euler's identity&lt;/a&gt;,
as usual when dealing with exponentials and complex numbers:&lt;/p&gt;
&lt;p&gt;%%
\begin{aligned}
e^{i\pi} = -1 &amp;amp;\iff e^{i\pi} = i^2\\
&amp;amp;\iff \log{e^{i\pi}} = \log{i^2}\\
&amp;amp;\iff i\pi = 2 \log{i}\\
&amp;amp;\iff \pi = 2\frac{\log{i}}{i}\\
&amp;amp;\iff \frac{\pi}{2} = \frac{\log{i}}{i}\\
&amp;amp;\iff \frac{\pi}{2} = -\log{i^i}\\
&amp;amp;\iff log(i^i) + \frac{\pi}{2} = 0\\ ■
\end{aligned}
%%&lt;/p&gt;
&lt;p&gt;Nothing too complicated indeed, and you can use this to get the value of
$$i^i$$, which is $$e^{-\frac{\pi}{2}}$$.&lt;/p&gt;</content><category term="mathematics"></category></entry><entry><title>Why you might want to use bcrypt for web applications</title><link href="https://dustri.org/b/why-you-might-want-to-use-bcrypt-for-web-applications.html" rel="alternate"></link><published>2025-06-25T16:15:00+02:00</published><updated>2025-06-25T16:15:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-06-25:/b/why-you-might-want-to-use-bcrypt-for-web-applications.html</id><summary type="html">&lt;p&gt;Passwords handling, despite its apparently triviality, is anything but.
It usually comes up in two distinct use-cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One needs to encrypt something, but only has a password to do so. This
   include for example password managers, disk/file/backups/… encryption.&lt;/li&gt;
&lt;li&gt;One needs to authenticate users in an interactive way, like …&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;Passwords handling, despite its apparently triviality, is anything but.
It usually comes up in two distinct use-cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One needs to encrypt something, but only has a password to do so. This
   include for example password managers, disk/file/backups/… encryption.&lt;/li&gt;
&lt;li&gt;One needs to authenticate users in an interactive way, like users logging
   on a website.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the former, the resources budget is pretty high: having your full-disk
encryption take a couple of seconds to unlock itself is not only acceptable,
but expected and kind of reassuring. For the latter, things are much more
constrained, and for the rest of this post, we'll focus on it.&lt;/p&gt;
&lt;p&gt;What we're trying to do here, is to make it as hard as possible for an attacker
in possession of the database of our website to bruteforce the hashes to obtain
the clear-text passwords of our users. As people tend to reuse passwords or
variations across services, password leaks are a valuable resource for
miscreants. And even if everyone was using unique passwords, storing them
hashed increases the time it takes for an attacker to compromise accounts,
increasing the odds that the breach will be discovered and passwords forcibly
changed before being misused.&lt;/p&gt;
&lt;p&gt;Let's have a look at what kind of levers we have at our disposition to make
the process of &lt;em&gt;cracking&lt;/em&gt; the hashes expensive for an attacker:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Computational hardness&lt;/strong&gt;: chain computations to make them hard to
   parallelize/distribute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory-hardness&lt;/strong&gt;: requiring a significant quantity of memory, forcing an
   attacker to get a ridiculous amount of it to bruteforce at scale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache-hardness&lt;/strong&gt;: making the computation move a lot of memory around or access
   it in fast weird/pseudo-random patterns, to eat a significant amount of bus
   bandwidth and force the attacker to put data outside of the CPU/GPU cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU-hardness&lt;/strong&gt;: make the attacker pay a proportionally huge CPU cost in
   exchange of reducing the memory requirements.&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;creation/release date&lt;/th&gt;
&lt;th&gt;computationally hard&lt;/th&gt;
&lt;th&gt;memory-hard&lt;/th&gt;
&lt;th&gt;cache-hard&lt;/th&gt;
&lt;th&gt;CPU-hard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/MD5"&gt;MD5&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1992&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/Bcrypt"&gt;bcrypt&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1999&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;barely&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/PBKDF2"&gt;PBKDF2&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc2898#page-9"&gt;2000&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/Scrypt"&gt;scrypt&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2009&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;a href="https://eprint.iacr.org/2016/989"&gt;yes&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/Argon2"&gt;Argon2&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;can be&lt;/td&gt;
&lt;td&gt;Argond2ds&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://en.wikipedia.org/wiki/Yescrypt"&gt;yescrypt&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.openwall.com/lists/announce/2018/03/09/1"&gt;2018&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For a small web application, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Can spend some CPU time computing the hash, but not too much, as users are
   expecting to be logged in almost instantaneously.&lt;/li&gt;
&lt;li&gt;Can't afford to have a significant amount of RAM consumed every time a user
   authenticates.&lt;/li&gt;
&lt;li&gt;Can absolutely afford to trash the caches.&lt;/li&gt;
&lt;li&gt;Don't really care about CPU hardness, as we can't afford to use a lot of
   memory anyway.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So our main lever in our case is cache-hardness, leaving us with 3 candidates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Argon2&lt;/strong&gt;: while there is a cache-hard variant (Argon2ds), it was added after
  the &lt;a href="https://password-hashing.net/"&gt;Password Hashing Competition&lt;/a&gt; ended,
  in its specification version v1.2.1, and thus isn't really implemented/used/
  anywhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;yescrypt&lt;/strong&gt;: too complex for small-scale deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bcrypt&lt;/strong&gt;: only barely cache-hard, due to its use
  of &lt;a href="https://en.wikipedia.org/wiki/Blowfish_(cipher)"&gt;Blowfish&lt;/a&gt; whose
  key-dependent s-boxes are taking 4k of memory, which is small compared
  to today's CPU/GPU L1 caches, but it's better than nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, bcrypt has &lt;a href="https://soatok.blog/2024/11/27/beyond-bcrypt/"&gt;some footguns&lt;/a&gt;,
but if you're using a proper language or a well-designed library, those will
handle them for you. Of course, if you're building a serious™ project, please
do reach out to your friendly neighborhood security person, as again, password
handling is a hard problem.&lt;/p&gt;
&lt;p&gt;If you'd like to learn more on the topic, I'd recommend Solar Designer's
&lt;a href="https://www.openwall.com/presentations/Passwords14-Energy-Efficient-Cracking/"&gt;Energy-efficient bcrypt
cracking&lt;/a&gt;
and &lt;a href="https://www.openwall.com/presentations/BSidesLjubljana2017-Yescrypt-Large-scale-Password-Hashing/BSidesLjubljana2017-Yescrypt-Large-scale-Password-Hashing.pdf"&gt;yescrypt: large-scale password
hashing&lt;/a&gt;,
as well as Niels Provos' &lt;a href="https://www.usenix.org/publications/loginonline/bcrypt-25-retrospective-password-security"&gt;Bcrypt at 25: A Retrospective on Password
Security&lt;/a&gt;,
the &lt;a href="https://eprint.iacr.org/2015/265.pdf"&gt;Password Hashing Competition - Survey and
Benchmark&lt;/a&gt;, Steve Thomas' &lt;a href="https://www.youtube.com/watch?v=VwzNw018ETc"&gt;bscrypt - A
Cache Hard Password Hash&lt;/a&gt; talk,
&lt;a href="https://soatok.blog/tag/password-hashing/"&gt;Soatok's blog posts on the topic&lt;/a&gt;,
and more generally, the &lt;a href="https://hashcat.net/"&gt;hashcat&lt;/a&gt;,
&lt;a href="https://hashmob.net/"&gt;HashMob&lt;/a&gt; and &lt;a href="https://openwall.com/john/"&gt;John the
Ripper&lt;/a&gt; password cracking communities.&lt;/p&gt;</content><category term="security"></category></entry><entry><title>My experience with Canonical's interview process</title><link href="https://dustri.org/b/my-experience-with-canonicals-interview-process.html" rel="alternate"></link><published>2025-06-01T09:30:00+02:00</published><updated>2025-06-01T09:30:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-06-01:/b/my-experience-with-canonicals-interview-process.html</id><summary type="html">&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;I &lt;a href="https://dustri.org/b/leaving-google.html"&gt;left Google&lt;/a&gt; in April 2024, and have thus
been casually looking for a new job during 2024. A good friend of mine is currently working
at &lt;a href="https://canonical.com/"&gt;Canonical&lt;/a&gt;, and he told me that it's quite a nice
company with a great working environment. Unfortunately,
the internet is full of …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;I &lt;a href="https://dustri.org/b/leaving-google.html"&gt;left Google&lt;/a&gt; in April 2024, and have thus
been casually looking for a new job during 2024. A good friend of mine is currently working
at &lt;a href="https://canonical.com/"&gt;Canonical&lt;/a&gt;, and he told me that it's quite a nice
company with a great working environment. Unfortunately,
the internet is full of people who had a poor experience:
&lt;a href="https://www.glassdoor.com/Interview/Canonical-Interview-Questions-E230560.htm"&gt;Glassdoor&lt;/a&gt;
shows that only 15% had a positive interview experience,
famous internet denizens like &lt;a href="https://hachyderm.io/@sara/112117125241735836"&gt;sara&lt;/a&gt;
rambled on the topic,
&lt;a href="https://www.reddit.com/search/?q=canonical"&gt;reddit&lt;/a&gt;,
&lt;a href="https://news.ycombinator.com/item?id=31426558"&gt;hacker&lt;/a&gt;&lt;a href="https://news.ycombinator.com/item?id=37059857"&gt;news&lt;/a&gt;,
&lt;a href="https://uk.indeed.com/cmp/Canonical"&gt;indeed&lt;/a&gt;
and
&lt;a href="https://www.teamblind.com/post/canonical-interview-process-is-such-bogus-ojbjgana"&gt;blind&lt;/a&gt;
all say it's terrible, … but the idea of being decently paid to do security
work on a popular Linux distribution was really appealing to me.&lt;/p&gt;
&lt;h2&gt;First application&lt;/h2&gt;
&lt;p&gt;I first applied there in October 2023. Canonical's &lt;a href="https://canonical.com/careers"&gt;careers'
website&lt;/a&gt; asks a bunch of odd questions like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;How did you perform in mathematics at high school?&lt;/li&gt;
&lt;li&gt;How did you perform in your native language at high school?&lt;/li&gt;
&lt;li&gt;Please share your rationale or evidence for the high school performance
  selections above. Make reference to provincial, state or nation-wide scoring
  systems, rankings, or recognition awards, or to competitive or selective
  college entrance results such as SAT or ACT scores, JAMB, matriculation
  results, IB results etc. We recognise every system is different but we will
  ask you to justify your selections above.&lt;/li&gt;
&lt;li&gt;What was your bachelor's university degree result, or expected result if you
  have not yet graduated? Please include the grading system to help us
  understand your result e.g. ‘85 out of 100’, ‘2:1 (Grading system: first
  class, 2:1, 2:2, third class)’ or ‘GPA score of 3.8/4.0 (predicted)’. We have
  hired outstanding individuals who did not attend or complete university. If
  this describes you, please continue with your application and enter ‘no
  degree’.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I was applying for a &lt;em&gt;senior position&lt;/em&gt;, and because there was no such thing as
ranking in my entire scholarship, I didn't think much about this, and wrote
that I wasn't bad at school, and that there was no ranking. I got instantly
rejected. I asked around, and some Canonical employees reached out to me on
&lt;a href="https://infosec.exchange/@jvoisin"&gt;mastodon&lt;/a&gt; to tell me that I should lie on
this step of the hiring process, as people who aren't in the top 10% in
high-school are automatically rejected. So I made things up, and didn't get
rejected this time.&lt;/p&gt;
&lt;p&gt;I then got an email about the "written interview", asking me to provide my
answers to &lt;a href="https://dustri.org/b/files/canonical_questions.txt"&gt;38 questions&lt;/a&gt; in a PDF.
It took me a couple of hours to write it down, boiling down to 21 pages of
text. Once sent, I was asked to do &lt;del&gt;modern
&lt;a href="https://en.wikipedia.org/wiki/Phrenology"&gt;phrenology&lt;/a&gt;&lt;/del&gt; "psychometric
assessments" from &lt;a href="https://www.thomas.co/"&gt;Thomas&lt;/a&gt;. The first one is called the
General Intelligence Assessment, and features with questions like those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Bob isn't as fast as Carl" → Who is the fastest? Carl or Bob?&lt;/li&gt;
&lt;li&gt;"a B f H" vs "k b j z" → how many letters in common? (1)&lt;/li&gt;
&lt;li&gt;Given 3 numbers, find the bigger and smaller, which one is the farthest from the middle one?&lt;/li&gt;
&lt;li&gt;Given a group of 3 words, which one has nothing to do with the 2 other?&lt;/li&gt;
&lt;li&gt;Given a pair of letter "R", with some rotated and some mirrored, how many are
  only rotated?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second one is the Behavioural Assessment, and is based on &lt;a href="https://www.thomas.co/thomas-candidate-test"&gt;picking "the
word that corresponds the most to your personality and the one that corresponds
the least"&lt;/a&gt; for 30 minutes. Their
"methodology" is based on the &lt;a href="https://en.wikipedia.org/wiki/DISC_assessment"&gt;DISC
assessment&lt;/a&gt; from 1928 which is
completely made-up pseudo-science. Heck, even their &lt;a href="https://www.thomas.co/sites/default/files/thomas-files/2024-01/Science-behind-Thomas-Behaviour-assessment-Jan-2024.pdf"&gt;brochure&lt;/a&gt;
only has 5 references with none from after 1957, and the 5 mentioned "studies" don't
have sources, data, details, … This made me equally amused and worried.&lt;/p&gt;
&lt;p&gt;The technical interviews ("Ubuntu Skills Interview", "Security Skills
Interview", "General Management Skills Interview") felt a bit empty
content-wise, and sounded more like some random conversation with open-source
enthusiast people at a bar. The only technical questions I remember were "What's your
favourite git command" and "Can you tell me about Ubuntu packaging". Keep in
mind that the position I was applying for was "Ubuntu Engineering Manager", so
I was expecting a lot of technical questions. Don't get me wrong, the
conversations were really nice, and I really liked the reflections on
Canonical's positions and philosophy.&lt;/p&gt;
&lt;p&gt;In December, I had an HR interview with a "Talent Science Partner", which was a
regular bland
&lt;a href="https://en.wikipedia.org/wiki/Situation,_task,_action,_result"&gt;STAR&lt;/a&gt;
questionnaire. Here is some feedback from the interviewer: "In the first 5
minutes of the call, I asked them about their biggest achievement at NBS and
they replied "Apparently you haven't read my 20-pages written interview". I
then explained to him that I have to ask the same questions to all candidates
and they offered me a terse answer." What's the point of asking for an
extensive written interview with those very same questions,
only for it to be completely ignored? It felt disrespectful to me.
Also, amusingly "During our interview, they will [sic.] be typing away.", so
candidates aren't expected to take notes. I was simply writing the questions
down, as well as some of my answers, likely the very same thing that the
interviewer was doing.&lt;/p&gt;
&lt;p&gt;A couple of hours later, I got a "Follow up - Benefits at Canonical" email,
listing all the benefits, but less than 24h after, I got the &lt;strong&gt;very same&lt;/strong&gt;
automated rejection email I got when I first applied in October. I sent an
email to enquire about feedback but never got a reply. During the whole
process, I was not once able to ask questions to a recruiter.&lt;/p&gt;
&lt;h2&gt;Second application&lt;/h2&gt;
&lt;p&gt;A couple of months later, I decided to reapply, hoping that maybe the previous
rejection was a misunderstanding or whatnot, even though seeing that
Canonical &lt;a href="https://www.linkedin.com/company/canonical/jobs/"&gt;had more than 32 000&lt;/a&gt;
job openings &lt;del&gt;smelt like bullshit&lt;/del&gt; was worrying.&lt;/p&gt;
&lt;p&gt;I applied both for a Manager position and an Individual Contributor one. I got
instantly rejected for the former via an automated email, sent twice; but was
invited to continue the process for the latter, via the "Fast Track - Security."
I learnt that this didn't mean that there would be less interviews or that the
process would somehow be faster, but simply that my resume was interesting
enough to warrant interviewing me before picking a team for me to fit in, a bit
like how Google is hiring.&lt;/p&gt;
&lt;p&gt;I re-used the written
interview, as the questions didn't really change. This time, I also had to
spend 2h on &lt;a href="https://devskiller.com"&gt;DevSkiller&lt;/a&gt; for a bland-at-best "Python
test." The first part was questions like "Which ones of those words aren't
python logging levels: URGENT, CRITICAL, INFO, FATAL, TRACE, …" or "What does
this small python snippet output" which is a matter to copy/pasting in into a
python interpreter locally. The second part was LeetCode-like exercises, but
since there were no humans involved, odds are that the only piece of
information that can be extracted from the candidate is "can they successfully
paste the question verbatim into a search engine/LLM."&lt;/p&gt;
&lt;p&gt;Funnily enough, while I could re-use my "psychometric assessments," I chose to pass
the tests again, so I could compare the results, and of course, they showed some
differences. This was followed by a weird "The security
mission and roles at Canonical" email from &lt;a href="https://en.wikipedia.org/wiki/Mark_Shuttleworth"&gt;Mark
Shuttleworth&lt;/a&gt; himself, with a
Message-ID &lt;code&gt;…prod-greenhouse-sidekiq-automation-worker…&lt;/code&gt;, meaning it's
another generic automated email, sigh. Then came the interviews. I
systematically asked the following questions in all but the final one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What do you think about the interview process?&lt;ul&gt;
&lt;li&gt;I often got praise about the written interview part, albeit nobody liked
  the process as a whole. Some high-in-the-chain people told me that they
  didn't really like spending time reviewing CV and interviewing people for
  a couple of hours every week. Heck, some of them that interviewed me
  weren't even going to work with me.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Do you like working at Canonical?&lt;ul&gt;
&lt;li&gt;The answers were a resounding &lt;strong&gt;yes&lt;/strong&gt;, which kept me motivated to go through the process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How is the upper-management, especially Mr. Shuttleworth, as I'll have an
  interview with him and it feels a bit weird, but also because I've heard
  things™?&lt;ul&gt;
&lt;li&gt;Those who work/worked with him told me (I took notes) that he was
&lt;em&gt;peculiar&lt;/em&gt;, &lt;em&gt;involved&lt;/em&gt;, &lt;em&gt;intense&lt;/em&gt;, &lt;em&gt;special&lt;/em&gt;, &lt;em&gt;opinionated&lt;/em&gt;, &lt;em&gt;could come
across as rude/harsh/know-it-all&lt;/em&gt;, and &lt;em&gt;sometimes difficult to work with&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I politely tried to gather feedback on the interviews, and was either told
  that they couldn't answer this question, or that I shouldn't need to worry as
  "everything looks green on the feedback."&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some interviews were pleasantly technical, and I really enjoyed the "Security
Deep Dive" one about confidential computing. The "Hiring Lead Interviews" felt
a bit useless, generic and similar, but provided some welcome colouring to how
it is to work at Canonical. Hilariously, someone from the team I applied for
told me that the role has been empty for more than 18 months, and offered a
polite smile when asked why she thought that was the case.&lt;/p&gt;
&lt;p&gt;The final interview was with Mark Shuttleworth. He didn't introduce himself,
which I found a bit odd. His first question was whether I was applying for a
managerial or a senior position, which didn't bode well: he had no idea what
position I was applying for, and thus wouldn't be asking role-related questions,
but likely only "vibe" ones. I got asked questions about high-school: how I
performed there, why did I pick a particular university, … I was so surprised
that I didn't think about asking on the spot how was any of this relevant for a
fucking &lt;em&gt;senior&lt;/em&gt; position. I did so afterwards, and was told that one of the sole
common point for all Canonical employees is that they all attended high-school,
so it provides a common base. Moreover, it gives some background, personal
history and shows the motivations and goals of the applicants. I don't know
about you, but when I was in high-school (around 15-20 years ago), my goals and
motivation were really different than my current ones, as they were mainly,
ranked in order of interest and importance: getting laid. &lt;/p&gt;
&lt;p&gt;To the question "How was your university?", I answered that it wasn't
prestigious, and pretty small and rural, as we could see cows from the windows.
Shuttleworth immediately interrupted me to say "don't play games, don't try to
muddle your answers. I'm interviewing you for a senior position, I'm asking you
questions, I'm expecting straight answers." I was so flabbergasted that instead
of answering properly ("As I'm interviewing for a senior position, I'm
expecting proper senior position related questions."), I gave a meek "Okay…"
Some parts of the conversation were
equally awkward and filled with an unhealthy amount of salt, especially about
&lt;a href="https://en.wikipedia.org/wiki/Upstart_(software)"&gt;upstart&lt;/a&gt; ("They're a reason
why Chromebooks are using it", the reasons are mostly technical
debt, not technical excellence.), &lt;a href="https://en.wikipedia.org/wiki/Mir_(software)"&gt;mir&lt;/a&gt; ("Wayland has the
same design flaws as Xorg"), … At some point, someone bought him a plate, and
he started to eat, without excusing himself about doing so. I asked him why he
would spend time interviewing prospective employees in non-executive positions,
let alone individual contributors,
as this is likely eating a lot of his time, given that Canonical currently has
around 1200 employees. He told me that he like to know who
is hired, and that this process allows to root out average candidates. After 40
minutes out of a 60 minutes scheduled interview, Shuttleworth said "Ok, nice
talking to you, have a nice day," and abruptly ended the interview. I seriously
thought about withdrawing my application, as I really didn't want to work with
him, but since the position was only senior IC, odds are that I wouldn't have
to, so I didn't retract it.&lt;/p&gt;
&lt;p&gt;A couple of days after, I got the now familiar automated rejection email. I
asked the hiring lead for feedback about why the rejection happened, but didn't
get a reply. Not once during all the interviews have I had a conversation about
compensation/salary/benefits/… &lt;/p&gt;
&lt;p&gt;So I exercised my 
&lt;a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation"&gt;GDPR&lt;/a&gt; rights,
and asked to be communicated everything pertaining to my
interviews. I got a bunch of documents, and the reason I was rejected was
"Culture/behaviour/motivation misalignment." Overall, would-you-hire-wise I got
three "strong yes", eight "yes", and a single "no" from Mark Shuttleworth, with
his feedback as following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This interview did not go well at all; the candidate initially gave
startlingly passive-aggressive responses to questions, in a way that I very
rarely see at this late stage of the process. Their application was a duplicate
with the same email address, and previously they had given a similar impression
in Talent Science. I would like to understand why that duplicate, and outcome,
were not noticed during this selection process.&lt;/p&gt;
&lt;p&gt;After some difficult exchanges I focused on the candidate's personal
interests, where they opened up. They are clearly passionate about low-level
technical details, but are only engaged on things that personally interest
them, with little evidence of teamwork or willingness to share load that is
uninteresting to them. They would be a poor fit for a team where balancing work
requires deriving some personal satisfaction from helping colleagues get things
done.&lt;/p&gt;
&lt;p&gt;In short, there are character issues here that we cannot address through
coaching and development.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, to be fair, everyone who knows me would likely agree that I'm not the most
empathetic person ever, and that communication isn't my strongest point,
despite me investing a lot of care and effort there, as it's an important topic
for me: I'm &lt;a href="https://en.wikipedia.org/wiki/Asperger_syndrome"&gt;Asperger&lt;/a&gt;,
meaning that a lot of social interactions, especially non-verbal and
implicit ones are often non-trivial for me, and that I tend to be (sometimes
overly) frank; but it's the very first time this came up as an issue, let
alone a prohibitive one, in a professional setting. The two other Hiring Lead
who &lt;em&gt;assessed&lt;/em&gt; my "Personality Traits" didn't find anything proscriptive there,
nor in any other categories for that matter. Interestingly, Shuttleworth's
feedback is the only one without any supporting notes nor direct quotes, and
reads more like an opinion piece than a proper artefact-supported assessment
like the rest.&lt;/p&gt;
&lt;p&gt;So now I'm really curious about the decision process here, as it seems that every
interviewer's opinion is ignored if Shuttleworth puts some red marks. Would the
outcome have been the same if it were someone else who had put them instead?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I was really looking forward to work at Canonical, being paid to work on
improving a popular Linux distribution security sounded really cool. I now
see that I should have, for once, listened to the collective hive-mind of the
internet, and not pour so much of my time and energy into this. I'm of course a
bit salty about the process, but not about the outcome, as it felt like I
dodged some kind of massive bullet.&lt;/p&gt;
&lt;p&gt;A friend suggested that I add some actionable advice hiring-wise to this
blogpost so that it doesn't read too much like an angry rant about not being
hired, but it felt pretentious to me. Moreover, as it seems that hiring at
Canonical is Shuttleworth's pet project, I don't think my opinion on the
topic will be useful in any way. Heck, I bet all the senior people spending
some of their expensive work time doing interviews are frustrated when
candidates they deem promising are rejected at the very of end on
Shuttleworth's whim; yet as this has apparently been going for a while now,
so I doubt a ranty article on my small corner on the internet would hold any sway.
So if I didn't write this article to complain, nor to make things change, why
bother? I wrote it because I would have loved to have read a post like this 
one while considering applying at Canonical, as it would have saved everyone
involved a tremendous amount of time.&lt;/p&gt;
&lt;p&gt;As a side note, it's completely ludicrous that I had to use the GDPR to get
some feedback on what went wrong on a job interview: the hiring lead could
simply have replied to my email with some high-level explanation, which would
have saved them from being GDPR'ed almost 300 pages of unredacted PDF.&lt;/p&gt;
&lt;p&gt;This article was apparently posted on &lt;a href="https://news.ycombinator.com/item?id=44149549"&gt;hacker
news&lt;/a&gt;,
the thread has some interesting testimonies as well. Since it was published, I
got some interesting tidbits/feedback from (ex-)canonical people: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;That "don't play games" comment, he pulled that shit all the time, the
mind-disrupting emotional suckerpunch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yep, it is indeed completely standard for Mark to nix strong candidates at
the last stage after everyone else has left positive feedback on them. And
roles stay open for years while everyone else tries to cover for them. This
process is "scientific" and "data-driven" and no internal argument about it is
brooked. Many other things about Canonical are great, but the hiring process
is grim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Amusingly, Canonical recently published a &lt;a href="https://ubuntu.com/blog/how-to-get-a-job-at-canonical"&gt;How to get a job at
Canonical&lt;/a&gt; blogpost,
see how many cases of your "toxic/worrying hiring practises" bingo cards it
can score!&lt;/p&gt;
&lt;h2&gt;Timeline&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2023/10/19: First time applying at Canonical&lt;/li&gt;
&lt;li&gt;2023/10/20: Automated rejection email&lt;/li&gt;
&lt;li&gt;2023/11/07: Told by Canonical employees that I should put "top 10%" to not get auto-rejected&lt;/li&gt;
&lt;li&gt;2023/11/??: Applied again&lt;/li&gt;
&lt;li&gt;2023/11/10: Written interview email&lt;/li&gt;
&lt;li&gt;2023/11/16: Psychometric assessment for Ubuntu Security Manager at Canonical - General Intelligence Assessment email&lt;/li&gt;
&lt;li&gt;2023/12/11: General Management Skills Interview with Person 1&lt;/li&gt;
&lt;li&gt;2023/12/12: Ubuntu Skills Interview with Person 2&lt;/li&gt;
&lt;li&gt;2023/12/12: Security Skills Interview with Person 3&lt;/li&gt;
&lt;li&gt;2024/01/11: Interview with HR with Person 4&lt;/li&gt;
&lt;li&gt;2024/01/11: "Benefits at Canonical" email&lt;/li&gt;
&lt;li&gt;2024/01/12: Automated rejection email&lt;/li&gt;
&lt;li&gt;2024/06/15: Second time applying at Canonical&lt;/li&gt;
&lt;li&gt;2024/06/18: Leetcode test at &lt;a href="https://devskiller.com/"&gt;DevSkiller&lt;/a&gt; email&lt;/li&gt;
&lt;li&gt;2024/07/01: "Psychometric tests" email&lt;/li&gt;
&lt;li&gt;2024/07/15: "We're excited to move forward with interviews for Security Software Engineer at Canonical." email&lt;/li&gt;
&lt;li&gt;2024/07/18: Software architecture and engineering skills interview with Person 5&lt;/li&gt;
&lt;li&gt;2024/07/19: Linux system skills interview with Person 6&lt;/li&gt;
&lt;li&gt;2024/07/19: Security deep-dive interview with Person 7&lt;/li&gt;
&lt;li&gt;2024/08/04: "Behavioural assessment for Security Software Engineer at Canonical" email&lt;/li&gt;
&lt;li&gt;2024/08/05: Met &lt;a href="https://www.linkedin.com/in/stephanie-domas/"&gt;Stephanie Domas&lt;/a&gt; (Canonical's CISO) at &lt;a href="https://dustri.org/b/modern-anti-abuse-mechanisms-in-competitive-video-games-at-black-hat-2024.html"&gt;Black Hat&lt;/a&gt;,
    who recommended me to apply at Canonical, and even got a warm
    recommendation from &lt;a href="https://www.linkedin.com/in/christopher-domas-39b3a5102/"&gt;her husband&lt;/a&gt;
    whom I've &lt;a href="https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html"&gt;met almost a decade ago at REcon&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;2024/08/20: Talent Interview with Person 8&lt;/li&gt;
&lt;li&gt;2024/08/22: Hiring Lead Interview with Hiring Lead Person 9&lt;/li&gt;
&lt;li&gt;&lt;del&gt;2024/08/29: Hiring Lead Interview, with Person 10&lt;/del&gt; cancelled&lt;/li&gt;
&lt;li&gt;&lt;del&gt;2024/08/29: Hiring Lead Interview, with Person 11&lt;/del&gt; cancelled&lt;/li&gt;
&lt;li&gt;2024/09/03: Hiring Lead Interview, with Person 10&lt;/li&gt;
&lt;li&gt;2024/09/04: Hiring Lead Interview, with Person 11&lt;/li&gt;
&lt;li&gt;2024/09/13: Hiring Lead Interview, with Person 12&lt;/li&gt;
&lt;li&gt;2024/09/23: Hiring Lead Interview, with Person 13&lt;/li&gt;
&lt;li&gt;2024/09/27: Hiring Lead Interview, with Mark Shuttleworth&lt;/li&gt;
&lt;li&gt;2024/09/30: Generic rejection email&lt;/li&gt;
&lt;li&gt;2024/09/30: Sent an email to the Hiring Lead asking for feedback&lt;/li&gt;
&lt;li&gt;2024/10/08: Sent an email to &lt;code&gt;dataprotection@canonical.com&lt;/code&gt; exercising my &lt;a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation"&gt;GDPR&lt;/a&gt; rights to get information about why I was rejected&lt;/li&gt;
&lt;li&gt;2024/10/30: Got the GDPR info, 300 pages of PDF.&lt;/li&gt;
&lt;li&gt;2025/06/01: Got pinged by a friend of mine about "that canonical article", so decided to publish it.&lt;/li&gt;
&lt;/ul&gt;</content><category term="rant"></category></entry><entry><title>Archspire - Relentless Mutation</title><link href="https://dustri.org/b/archspire-relentless-mutation.html" rel="alternate"></link><published>2025-05-22T18:15:00+02:00</published><updated>2025-05-22T18:15:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-05-22:/b/archspire-relentless-mutation.html</id><summary type="html">&lt;p&gt;&lt;a href="https://archspire.bandcamp.com/album/relentless-mutation"&gt;&lt;img alt="Archspire - Relentless Mutation cover" src="https://dustri.org/b/images/archspire_relentless_mutation.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm a huge fan of &lt;em&gt;technical death metal&lt;/em&gt;, from the old stuff like
&lt;a href="https://en.wikipedia.org/wiki/Cynic_(band)"&gt;Cynic&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Necrophagist"&gt;Necrophagist&lt;/a&gt;, to
the newest-ish &lt;a href="https://en.wikipedia.org/wiki/Obscura_(band)"&gt;Obscura&lt;/a&gt;,
&lt;a href="https://equipoiseofficial.bandcamp.com/"&gt;Equipoise&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Beyond_Creation"&gt;Beyond Creation&lt;/a&gt;.
Unfortunately, one the common issues with this sub-genre is that
it tends to be technical for the sake of it,
resulting in insipid stuffing of pointlessly …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://archspire.bandcamp.com/album/relentless-mutation"&gt;&lt;img alt="Archspire - Relentless Mutation cover" src="https://dustri.org/b/images/archspire_relentless_mutation.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm a huge fan of &lt;em&gt;technical death metal&lt;/em&gt;, from the old stuff like
&lt;a href="https://en.wikipedia.org/wiki/Cynic_(band)"&gt;Cynic&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Necrophagist"&gt;Necrophagist&lt;/a&gt;, to
the newest-ish &lt;a href="https://en.wikipedia.org/wiki/Obscura_(band)"&gt;Obscura&lt;/a&gt;,
&lt;a href="https://equipoiseofficial.bandcamp.com/"&gt;Equipoise&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Beyond_Creation"&gt;Beyond Creation&lt;/a&gt;.
Unfortunately, one the common issues with this sub-genre is that
it tends to be technical for the sake of it,
resulting in insipid stuffing of pointlessly technical technicalities all
around on top of wanking on never-ending licks and blast beats, without any
consideration for consistency, structure building, let alone artistic taste.&lt;/p&gt;
&lt;p&gt;But, not Archspire! &lt;a href="https://en.wikipedia.org/wiki/Relentless_Mutation"&gt;Relentless
Mutation&lt;/a&gt; is the third
full-length from this Canadian band, released on the 22nd of September 2017 via
Season of Mist. Surprisingly short by clocking at only 31 minutes, but if it
was played at "normal" speed it would likely be around 60min I guess. The tracks are
flowing into each others, while being completely distinct despite being, well
"technical death metal". It's one of the few albums where it's trivial to
remember which song was which after a few listening, which while being a
low-low bar, is unfortunately worth noting. Moreover, the album is surprisingly
melodic: one can hum the tracks, which is again, low bar, yet again needs to be
mentioned. It never feels like they're being fast for the sake of being fast:
the music is shockingly great, not some pointless tech death speedrun
any% shredding.&lt;/p&gt;
&lt;p&gt;The musicianship on this album is absolutely incredible and it helps that it
can actually be heard in the mix: Unlike their previous albums &lt;a href="https://archspire.bandcamp.com/album/the-lucid-collective"&gt;The Lucid
Collective&lt;/a&gt; and &lt;a href="https://musicbrainz.org/release/689f0722-8ff4-436d-a7c1-4d7cf216bad6"&gt;All
Shall
Align&lt;/a&gt;,
the mixing is &lt;strong&gt;way better&lt;/strong&gt;: no more lyrics relayed to a muted background
noise or fuzzy guitars. Things are detailed and crisp, everything in its right
place and nothing feels too loud or too quiet. And given the complexity, speed
and layering of the music, it's no small feat to achieve something this clear
cut!&lt;/p&gt;
&lt;p&gt;Now, it's impossible to write this without sounding
cliche, but the guitarists and bassists truly take technical playing to a whole
new level. The sheer speed, precision, and creativity of their riffs in
literally every song is undeniably jaw dropping, with some clear neo-classic
influences. Something that makes the whole album utterly pleasant is that the
melodies never seem to follow exactly where the ear would take them, always
surprising the listener. While guitar solo aren't my jam, as their tend to be, once again, aimless and
intrusive wanking on tedious licks, it's not the case here: they don't feel out
of place, and are often slower than the main riffs, as I guess they can't play
much faster anyway.&lt;/p&gt;
&lt;p&gt;If I had to bring some negativity, I'd say that Oli Peters' singing technique,
while impressive, could use some more diction. If black metal bands like
&lt;a href="https://dustri.org/b/baa-deus-qui-non-mentitur.html"&gt;Bâ'a&lt;/a&gt; can manage to have understandable singing,
odds are that so can other too. It's still completely insane how he manages to
deliver lyrics at such high-speed nonetheless, and surprisingly for the genre,
the lyrics are &lt;a href="https://www.heavyblogisheavy.com/2021/10/05/prognotes-archspire-relentless-mutation/"&gt;surprisingly good&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a friend puts it, in this age of AI slop everywhere, given how fast and
square Archspire is, it's the robots that should be afraid of being replaced.&lt;/p&gt;</content><category term="music"></category></entry><entry><title>Making Burp Suite snappy on Asahi Linux</title><link href="https://dustri.org/b/making-burp-suite-snappy-on-asahi-linux.html" rel="alternate"></link><published>2025-05-02T15:00:00+02:00</published><updated>2025-05-02T15:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-05-02:/b/making-burp-suite-snappy-on-asahi-linux.html</id><summary type="html">&lt;p&gt;I've been using &lt;a href="https://asahilinux.org/"&gt;Asahi Linux&lt;/a&gt; for a couple of months now, and I'm pretty happy
with it. There are of course some minor issues, mostly software not being available
there, like &lt;a href="https://signal.org"&gt;Signal&lt;/a&gt; (thanks opensuse for &lt;a href="https://build.opensuse.org/project/show/network:im:signal"&gt;providing
builds&lt;/a&gt;). Today's
papercut is &lt;a href="https://portswigger.net/burp"&gt;Burp Suite&lt;/a&gt; being laggy and eating a
worryingly high amount …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been using &lt;a href="https://asahilinux.org/"&gt;Asahi Linux&lt;/a&gt; for a couple of months now, and I'm pretty happy
with it. There are of course some minor issues, mostly software not being available
there, like &lt;a href="https://signal.org"&gt;Signal&lt;/a&gt; (thanks opensuse for &lt;a href="https://build.opensuse.org/project/show/network:im:signal"&gt;providing
builds&lt;/a&gt;). Today's
papercut is &lt;a href="https://portswigger.net/burp"&gt;Burp Suite&lt;/a&gt; being laggy and eating a
worryingly high amount of CPU. &lt;a href="https://social.treehouse.systems/@chaos_princess"&gt;&lt;code&gt;chaos_princess&lt;/code&gt;&lt;/a&gt;
suggested some workarounds for whatever Java application someone else wanted to
run, and I thought it might have the same root cause.&lt;/p&gt;
&lt;p&gt;Java &lt;a href="https://docs.oracle.com/en/java/javase/22/troubleshoot/java-2d-pipeline-rendering-and-properties.html#GUID-7637EE64-D83C-404D-8475-489ECFA8143B"&gt;supports OpenGL hardware
acceleration&lt;/a&gt;
since
&lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/2d/new_features.html#ogl"&gt;Java5&lt;/a&gt;,
but for whatever reason that I'm too lazy to figure out, it's not enabled by
default on Asahi. Just add &lt;code&gt;-Dsun.java2d.opengl=True&lt;/code&gt; to the
&lt;code&gt;BurpSuitePro.vmoptions&lt;/code&gt; in your Burp installation folder, and you're good to
go: Burp's interface shouldn't gobble a ridiculous amount of watts and by laggy
anymore.&lt;/p&gt;
&lt;p&gt;If you see some pink textures, you can add &lt;code&gt;-Dsun.java2d.opengl.fbobject=false&lt;/code&gt;
as well, to &lt;a href="https://docs.oracle.com/en/java/javase/22/troubleshoot/java-2d-pipeline-rendering-and-properties.html#GUID-414C9563-2904-4F4C-81F7-1ACF863FCDB2"&gt;disable
&lt;code&gt;GL_EXT_framebuffer_object&lt;/code&gt;&lt;/a&gt;.
Apparently, it "extension provides better performance for rendering and reduced
VRAM consumption when using &lt;code&gt;VolatileImages&lt;/code&gt;", but I haven't noticed a
difference either way. &lt;/p&gt;</content><category term="security"></category></entry><entry><title>Mirroring my git repositories</title><link href="https://dustri.org/b/mirroring-my-git-repositories.html" rel="alternate"></link><published>2025-04-02T16:00:00+02:00</published><updated>2025-04-02T16:00:00+02:00</updated><author><name>jvoisin</name></author><id>tag:dustri.org,2025-04-02:/b/mirroring-my-git-repositories.html</id><summary type="html">&lt;p&gt;Since &lt;a href="https://en.wikipedia.org/wiki/Enshittification"&gt;everything is going downhill on the internet&lt;/a&gt;,
I spent some time mirroring some of my git repositories on a machine at home.
I chose &lt;a href="https://git.zx2c4.com/cgit/about/"&gt;cgit&lt;/a&gt; for the interface, as
everything else is fucking terrible at best. The deployment is trivial: install
&lt;code&gt;cgit&lt;/code&gt; and &lt;code&gt;fastcgi&lt;/code&gt;, create a &lt;code&gt;git&lt;/code&gt; user with …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since &lt;a href="https://en.wikipedia.org/wiki/Enshittification"&gt;everything is going downhill on the internet&lt;/a&gt;,
I spent some time mirroring some of my git repositories on a machine at home.
I chose &lt;a href="https://git.zx2c4.com/cgit/about/"&gt;cgit&lt;/a&gt; for the interface, as
everything else is fucking terrible at best. The deployment is trivial: install
&lt;code&gt;cgit&lt;/code&gt; and &lt;code&gt;fastcgi&lt;/code&gt;, create a &lt;code&gt;git&lt;/code&gt; user with &lt;code&gt;/src/git&lt;/code&gt; as home, slap the
following into your nginx configuration and you're good to go:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git.dustri.org&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/share/webapps/cgit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;try_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;@cgit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;^.+\.(css|png|ico)&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/share/webapps/cgit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;expires&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;30d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;@cgit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;SCRIPT_FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$document_root/cgit.cgi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PATH_INFO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;QUERY_STRING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;unix:/var/run/fcgiwrap/fcgiwrap.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://git.zx2c4.com/cgit/tree/cgitrc.5.txt"&gt;configuration&lt;/a&gt; for &lt;code&gt;cgit&lt;/code&gt; is
also super-simple:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="na"&gt;virtual-root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;
&lt;span class="na"&gt;scan-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/srv/git&lt;/span&gt;
&lt;span class="na"&gt;clone-prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://git.dustri.org&lt;/span&gt;
&lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="na"&gt;section-from-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;repository-sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;age&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I &lt;code&gt;git clone&lt;/code&gt;'d the repositories I wanted to mirror into &lt;code&gt;/srv/git&lt;/code&gt; via &lt;code&gt;git
clone --mirror …&lt;/code&gt;, and wrote a shell script to kept them updated:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/srv/git/*/&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[+] Updating &lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;--git-dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;update
&lt;span class="w"&gt;    &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;--git-dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--no-pager&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;--format&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%as&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/packed-refs&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As &lt;code&gt;cgit&lt;/code&gt; is using &lt;code&gt;packed-refs&lt;/code&gt; to determine the last time a git repository
was updated, I set its modification date to the latest's commit one. Using
&lt;code&gt;--format=%ai&lt;/code&gt; would be better (&lt;a href="https://en.wikipedia.org/wiki/ISO_8601"&gt;ISO
8601&lt;/a&gt;), but busybox' &lt;code&gt;touch&lt;/code&gt; doesn't
support it, so &lt;code&gt;%as&lt;/code&gt; (&lt;code&gt;YYYY-MM-DD&lt;/code&gt;) has to suffice. The script is called via the
&lt;code&gt;git&lt;/code&gt;'s user crontab every day.&lt;/p&gt;
&lt;p&gt;For private repositories on github, I generated a per-repo &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens"&gt;personal access
token&lt;/a&gt;
and cloned each of them via &lt;code&gt;git clone --mirror https://jvoisin:github_pat_…@github.com/jvoisin/my_secret_repo&lt;/code&gt;.
Preventing them from being listed on the web interface is done by putting a
&lt;code&gt;cgitrc&lt;/code&gt; file with &lt;code&gt;hide=1&lt;/code&gt; or &lt;code&gt;ignore=1&lt;/code&gt; at their root depending of what you
prefer.&lt;/p&gt;
&lt;p&gt;You can see the result on &lt;a href="https://git.dustri.org/"&gt;git.dustri.org&lt;/a&gt;.&lt;/p&gt;</content><category term="sysadmin"></category></entry></feed>