<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like break-everything-fuzz-testing, understanding-docker-volume-mounts, why-you-should-be-using-https but not coming-around-on-llms, debugging-beyond-the-debugger</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/break-everything-fuzz-testing,understanding-docker-volume-mounts,why-you-should-be-using-https/unlike/coming-around-on-llms,debugging-beyond-the-debugger/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2026-04-09T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>The Case of the Unchanging Config</title>
        <link href="https://chameth.com/the-case-of-the-unchanging-config/"/>
        <updated>2026-04-09T00:00:00Z</updated>
        <id>https://chameth.com/the-case-of-the-unchanging-config/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Last week I was attempting to make it so I could share pictures on IRC directly from my client. This sounds simple, but it involves a bouncer&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; that proxies the request to a standalone image hosting service that I had to modify to be compatible. At one point my testing loop was:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a change to the hosting service&lt;/li&gt;
&lt;li&gt;Commit it&lt;/li&gt;
&lt;li&gt;Tag a new release&lt;/li&gt;
&lt;li&gt;Wait for it to build&lt;/li&gt;
&lt;li&gt;Update the version I’m running on my server&lt;/li&gt;
&lt;li&gt;Reconfigure the bouncer to pass the new parameter or change the URL or whatever&lt;/li&gt;
&lt;li&gt;Try uploading a photo from my phone&lt;/li&gt;
&lt;li&gt;Realise I’ve overlooked something and go back to step one&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I &lt;em&gt;could&lt;/em&gt; have set up a local copy of everything and tested it sensibly. I &lt;em&gt;should&lt;/em&gt; have set up a local copy of everything and tested it sensibly. But it seemed like such a trivial change, and setting up the whole environment seemed like such a pain. After the third or so iteration of failure I was pretty annoyed with myself, computers, and basically everything.&lt;/p&gt;
&lt;p&gt;My biggest annoyance was that my bouncer would not pick up the new URL from the config when I changed it. It’s meant to reload the config when it receives a &lt;code&gt;SIGHUP&lt;/code&gt;, and it claimed to in the logs, but I could clearly see it was still hitting the old URL. Restarting the bouncer to update the config is a pain, as it disconnects me from all the IRC networks, and has to reconnect to them all, reauthenticate, etc. It also mildly spams everyone who shares a channel with me&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;When I finally got everything working I had a look at the bouncer source, and thought I’d spotted the issue. I raised a bug report, ending in this remark:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It looks like the config is reloaded properly, but the handler for uploads is created once at startup and has its own copy of the uploader, so effectively snapshots the config to whatever it is at startup:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nx&#34;&gt;fileUploadHandler&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;HandlerFunc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;srv&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;Config&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;fileupload&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;Handler&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;Uploader&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;FileUploader&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;DB&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;Auth&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;Auth&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;HTTPOrigins&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;HTTPOrigins&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;ServeHTTP&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’m not quite sure what I thought I saw there, but that’s not right. I want to call it a hallucination, but that feels like a very overloaded word these days. I guess I was just seeing what I wanted to see, and that was a good excuse to stop investigating. Still, even if I misidentified the cause, the bug was still present, right? … Right?&lt;/p&gt;
&lt;h3 id=&#34;the-science-of-deduction&#34;&gt;The Science of Deduction&lt;/h3&gt;
&lt;p&gt;When the developer got back and said he couldn’t reproduce my issue, I went back to my install and immediately reproduced it. With a calmer head, I figured it was probably something with my particular set up. First thing to check: am I actually running the version I think I am?&lt;/p&gt;
&lt;p&gt;Unfortunately the bouncer doesn’t actually seem to expose the version anywhere that I can see. It’s not in the logs, it doesn’t have a &lt;code&gt;-version&lt;/code&gt; flag, and none of the IRC-based status commands seem to include it. But I know it’s a Go app, and I know Go embeds the version information. &lt;code&gt;go version -m &amp;lt;binary&amp;gt;&lt;/code&gt; will dump it all out, but the binary is inside a Docker image, and the Docker image is one of my &lt;a href=&#34;https://chameth.com/artisanal-docker-images/&#34;&gt;nice, minimal, artisanal ones&lt;/a&gt; so doesn’t ship a &lt;code&gt;go&lt;/code&gt; binary. No problem, &lt;code&gt;docker compose cp bouncer:/bnc ./bnc&lt;/code&gt; yoinks the binary out of the container, and then dumping the version shows that, yes, I am running the version I thought I was. Hmm.&lt;/p&gt;
&lt;p&gt;The next tool I reached for in &lt;a href=&#34;https://chameth.com/debugging-beyond-the-debugger/&#34;&gt;my toolbox&lt;/a&gt; was &lt;code&gt;strace&lt;/code&gt;. Maybe it’s not actually reading the file for some reason? I immediately executed &lt;code&gt;strace -p &amp;lt;pid&amp;gt; -e trace=openat,open,read,pread64 -f&lt;/code&gt; without having to look any part of that up. Yep. Definitely. Then I edited the config, &lt;code&gt;HUP&lt;/code&gt;’d the bouncer, and saw that it was… reading the config file. As it’s meant to. By default &lt;code&gt;strace&lt;/code&gt; truncates strings to 32 bytes, so I couldn’t actually see the line I’d changed. Some more definitely-not-RTFMing later, and rerunning it with an extra &lt;code&gt;-s 65536&lt;/code&gt; let me see the full config. Surprise! The config hadn’t changed!&lt;/p&gt;
&lt;p&gt;To confirm my findings, I used &lt;code&gt;docker compose cp&lt;/code&gt; again, this time yoinking the config file from inside the container. The inside config file was definitely different to the outside config file. What? My hypothesis at this point was “something something Docker nonsense”. I mount the config as read-only, and was wondering if that meant that Docker was doing something &lt;em&gt;weird&lt;/em&gt; instead of just bind mounting it. A quick trip to &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/mounts&lt;/code&gt; showed that it was, in fact, not doing anything weird, and was just bind mounting it.&lt;/p&gt;
&lt;p&gt;If the file is bind mounted, then surely it’s the same file? I ran &lt;code&gt;stat&lt;/code&gt; on the file on the host, noted the inode number, then pondered how to actually run &lt;code&gt;stat&lt;/code&gt; on the file inside the container, given the aforementioned awkwardly minimal image. The solution was easy: access it via &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/root/&lt;/code&gt;. I could’ve saved myself a bunch of &lt;code&gt;docker compose cp&lt;/code&gt; if I’d thought about that earlier. Oh well. The inode of that file was different. What?&lt;/p&gt;
&lt;p&gt;The answer was DNS. It’s always DNS. Oh, sorry, force of habit. I meant the answer was &lt;em&gt;vim&lt;/em&gt;. I was editing the config in vim, and when it saves files, by default, it writes the new content to a temporary file and does an atomic rename. That’s normally a good thing: it prevents corruption if the write fails midway through&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. In this case, though, that means the new file has a new inode. Bind mounting a file binds to the inode, so the container just keeps clutching onto the original config from when it was started, blissfully unaware that the party has relocated down the street.&lt;/p&gt;
&lt;p&gt;This problem is likely to happen whenever you bind mount a file into a container. When I mentioned this to a friend, he immediately responded “oh yeah, never do that”, and went on to describe the horrible hacks he’s had to add to Ansible to sidestep the issue. The nicer solution is to just bind mount an entire directory if you can, as then it doesn’t matter what happens to the files within it. I really like having the config files sat alongside the Docker compose files, though; having to create a directory just to work around some bind mount weirdness upsets me.&lt;/p&gt;
&lt;p&gt;Now I knew what the problem was, I found there was an issue &lt;a href=&#34;https://github.com/moby/moby/issues/6011&#34;&gt;raised against Docker&lt;/a&gt; twelve years ago&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. The first response was “that’s expected”, and I fully agree with the author: “respectfully, that might be expected by you, but it was not expected by me”!&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; As a result of the issue they &lt;a href=&#34;https://github.com/moby/moby/pull/6854/changes&#34;&gt;added a nice note to the docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;
Many tools used to edit files including &lt;code&gt;vi&lt;/code&gt; and &lt;code&gt;sed --in-place&lt;/code&gt; may result
in an inode change. Since Docker v1.1.0, this will produce an error such as
“&lt;em&gt;sed: cannot rename ./sedKdJ9Dy: Device or resource busy&lt;/em&gt;”. In the case where
you want to edit the mounted file, it is often easiest to instead mount the
parent directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But in the intervening twelve years, both the note and the functionality described have gone missing. Ho-hum.&lt;/p&gt;
&lt;p&gt;I found it interesting how I’ve only just hit this problem, given how long I’ve used Docker. But I realised that almost everything I run I’m happy to just restart. Cattle, not pets, and so on. My IRC bouncer is one of the few exceptions to that. The only other thing I regularly hot reloaded was &lt;a href=&#34;https://github.com/csmith/centauri&#34;&gt;Centauri&lt;/a&gt;, my reverse proxy, but that had a whole config directory mounted because it was shared between containers, so nicely sidestepped the foot-gun.&lt;/p&gt;
&lt;p&gt;So lesson learnt: check for weird bind mount issues before raising issues about config hot reloading. It’ll join the esteemed company of “maybe the drive is full and causing completely unrelated problems?”, “perhaps everything is dog slow because the kernel ran out of entropy?”, and “did systemd sneakily take over that functionality while you weren’t looking?” in the troubleshooting checklist.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;An IRC bouncer is basically an always-on proxy. It connects to the IRC networks for you, then your clients connect to your bouncer. The bouncer can then send incoming messages to all your different clients, cache them when you’re offline and replay them later, and lots of other nice things people take for granted in their chat apps these days. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Join/part/quit spam is part of IRC, and clients have ways of handling it, but I still &lt;em&gt;feel&lt;/em&gt; bad about doing it excessively. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;You can disable this in vim by setting &lt;code&gt;backupcopy=yes&lt;/code&gt;. Good luck redoing all the debugging if you ever accidentally remove that from your &lt;code&gt;vimrc&lt;/code&gt;, though! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Which is weird, because Docker can’t possibly be that old. That would make me much older than I’m prepared to accept. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;If you read the thread they didn’t actually mean to sound so dismissive, but it’s still pretty funny. “Yes, it’s expected that the foot-gun causes your foot to hurt. Duh. What did you expect?” &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>How to break everything by fuzz testing</title>
        <link href="https://chameth.com/break-everything-fuzz-testing/"/>
        <updated>2020-04-26T00:00:00Z</updated>
        <id>https://chameth.com/break-everything-fuzz-testing/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/break-everything-fuzz-testing/chimp.jpg&#34; alt=&#34;Chimp sat at a typewriter&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;239&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Fuzz testing is a bit like the infinite monkey theorem, but instead of Shakespeare you get crashes.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Fuzz testing, if you’re not aware, is a form of testing that uses procedurally generated random
inputs to see how a program behaves. For instance, if you were fuzz testing a web page renderer
you might generate a bunch of HTML - some valid, and some not - and make sure the rendering
process didn’t unexpectedly crash.&lt;/p&gt;
&lt;p&gt;Fuzz testing doesn’t readily lend itself to all types of software, but it particularly shines
in cases where some kind of complex user input is accepted and processed in some way - like
the aforementioned web page renderer. I was recently adding a library to parse EXIF data to
images to an Internet-facing service and realised it was a perfect opportunity to do some fuzz
testing. Even if I didn’t find any issues, I’d improve my confidence that the library was safe
enough to expose to the Internet.&lt;/p&gt;
&lt;h3 id=&#34;breaking-my-exif-library&#34;&gt;Breaking my EXIF library&lt;/h3&gt;
&lt;p&gt;I wrote a quick harness to run &lt;a href=&#34;https://github.com/dvyukov/go-fuzz&#34;&gt;go-fuzz&lt;/a&gt; on the library,
and gave it some pre-existing demo files as sample input. The way go-fuzz works is that it
instruments your code and then mutates the inputs to try to improve the coverage. For example,
if I had some sample data that had an EXIF tag with a value of 1 then go-fuzz might change it
to a 2 and see if the code follows a different path. In most cases it won’t but when it does,
they tend to be very interesting cases.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;One of the first issues that go-fuzz found was that some values in a maker note field would cause
the library to panic (i.e., crash). This happened because there was a check to see if the first
six characters were “Nikon” and a null byte, without first checking to see if there were actually
six characters available. This is a kind of bug that doesn’t happen much with “real” data - as
the field is either not present or completed correctly - but could easily be exploited once this
code is exposed to the Internet.&lt;/p&gt;
&lt;p&gt;Another interesting bug that go-fuzz found was that if a tag had a particularly large count, the
library would try to allocate an obscene amount of memory and die. There was already a check in
the code that was meant to avoid this exact scenario, but go-fuzz managed to find a way around
it. Each tag has a size (for example an integer tag takes a fixed number of bytes) and a count;
the existing check multiplied the two together and made sure that the result wasn’t too large.
For most cases this was fine but go-fuzz found a case where the count was so large that when
multiplied by the size of the tag it overflowed the integer and became negative, thus passing
the sanity check but then subsequently failing when it came around to actually allocating the
memory.&lt;/p&gt;
&lt;p&gt;The final bug of note that go-fuzz found was the most interesting. EXIF data is stored in IFDs
(“Image File Directories”), and each IFD provides what is effectively a pointer (a byte offset)
to the next one. The EXIF library already had a check to make sure that these didn’t loop, but
it only checked the immediately preceding IFD - so if IFD 1 linked to IFD 2, it would catch IFD 2
linking back to IFD 1 and break the loop with an error. Go-fuzz found that having three interlinked
IFDs had the same issue, though, and the guard code wasn’t triggered. This created an infinite
loop, maxing out a CPU core until the process was eventually killed - one of the worst kind of
bugs you could have in an Internet-facing service which doesn’t deal with private data! The fix
for this was fairly straightforward - I just made the library keep a record of the previously
visited IFDs and bail out if it found a loop.&lt;/p&gt;
&lt;h3 id=&#34;breaking-my-ide&#34;&gt;Breaking my IDE&lt;/h3&gt;
&lt;p&gt;When go-fuzz detects an issue it outputs not only the details of the problem (the stack trace,
error message, and so forth) but also the input that generated the problem. This is useful for
reproducing and making sure the issue is fixed, but it also makes it really easy to write
a test to ensure that the behaviour never regresses in the future.&lt;/p&gt;
&lt;p&gt;As I was working through fixing the bugs that go-fuzz found, I dutifully added new tests where
needed. After adding the sample input with looping IFDs to the project, I switched to IDEA to
write a test to use it. I clicked on the input file to copy the file name, and then the entire
IDE hung and had to be restarted. Uh oh! When I restarted IDEA, it immediately began indexing
the project and again hung. It turns out IDEA parses EXIF data (presumably, even if it does
nothing else with the data, to get the rotation property for images), and the library they use -
an independent one written on Java - had the same bug as the Go library I was using.&lt;/p&gt;
&lt;p&gt;In order to stop IDEA from indexing the file and becoming unusable I renamed it from a ‘.tif’
extension to ‘.dat’, and everything went back to normal. I thought I’d best report the bug to
JetBrains, though, so they could put a proper fix in.&lt;/p&gt;
&lt;h3 id=&#34;breaking-youtrack&#34;&gt;Breaking YouTrack&lt;/h3&gt;
&lt;p&gt;JetBrains use their own issue tracker called YouTrack for reporting bugs in IDEA. I dutifully
went over and described the problem, attaching the log files from the IDE, a description of how
the file was malformed, and carefully selected the .dat version of the file to upload so that it
wouldn’t cause anyone else the same immediate problem.&lt;/p&gt;
&lt;p&gt;After trying to upload the file I got a strange error back. Uh oh! I submitted the IDEA issue as
it stood, unable to see if the attachments had even uploaded, and went and wrote up an issue for
YouTrack itself about the error message. While I was doing that, YouTrack seemed to slow down and
become really annoying to use. I had a sinking feeling the exact same thing was probably
happening as with IDEA and my library - but this time YouTrack had content-sniffed the file
instead of relying on the file extension. In hindsight, I should’ve put the file in a passworded
archive to ensure no automated tools got hold of it. I marked the issue as a security problem as in
a service like YouTrack it presents a denial-of-service opportunity&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; (remember when I said it was
one of the worst kinds of bugs you could have in an Internet-facing service?…)&lt;/p&gt;
&lt;p&gt;Shortly after I raised my YouTrack ticket, a notice appeared at the top of the page saying they
were investigating the current performance issues. Uh oh! I was holding out hope that this was
unrelated to me uploading the buggy dat file, but the timing all seemed a bit suspect. I shot
support an e-mail saying I think I might be the root cause for their performance issues and
linked to the ticket. In the time it took me to e-mail them, the entire site had been
put into maintenance mode. I got an e-mail back a few hours later confirming the outage
was in fact all my fault, as I’d feared. Within the space of days the JetBrains security team
had fixed the issue in YouTrack, which was a pretty nice turnaround.&lt;/p&gt;
&lt;p&gt;So if you were trying to access YouTrack at the start of March and couldn’t - I’m sorry, I didn’t
mean to! Also, if you’re building an Internet-facing service that takes user input you should
really consider running a fuzz tester against it!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;“We have a problem”. “Remember, there are no such things as problems,
only opportunities”. “Well then we have a DDoS opportunity.”
– &lt;a href=&#34;https://twitter.com/J4vv4D/status/671090709588496384&#34;&gt;@J4vv4d&lt;/a&gt; &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Understanding Docker volume mounts</title>
        <link href="https://chameth.com/understanding-docker-volume-mounts/"/>
        <updated>2019-04-01T00:00:00Z</updated>
        <id>https://chameth.com/understanding-docker-volume-mounts/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/understanding-docker-volume-mounts/logo.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/understanding-docker-volume-mounts/logo.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/understanding-docker-volume-mounts/logo.png&#34; alt=&#34;The Docker project logo&#34; loading=&#34;lazy&#34; width=&#34;271&#34; height=&#34;242&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The Docker project logo&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One thing that always confuses me with Docker is how exactly mounting
volumes behaves. At a basic level it’s fairly straight forward: you
declare a volume in a Dockerfile, and then either explicitly mount
something there or docker automatically creates an anonymous volume
for you. Done. But it turns out there’s quite a few edge cases…&lt;/p&gt;
&lt;h3 id=&#34;changing-ownership-of-the-folder&#34;&gt;Changing ownership of the folder&lt;/h3&gt;
&lt;p&gt;Perhaps the most common operation done on a Docker volume other than
simply mounting it is trying to change the ownership of the directory.
If your Docker process runs as a certain user you probably want the
directory to be writable by that user.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;At first we might try something like:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;alpine&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;RUN&lt;/span&gt; adduser -D -u &lt;span class=&#34;chroma-m&#34;&gt;1113&lt;/span&gt; test123&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;USER&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;test123&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;VOLUME&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;/testing&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But changing the user doesn’t seem to have any effect on the volume.
Why? Checking the docs for the
&lt;a href=&#34;https://docs.docker.com/engine/reference/builder/#user&#34;&gt;&lt;code&gt;USER&lt;/code&gt; instruction&lt;/a&gt;
shows that only affects certain future operations — namely
&lt;code&gt;RUN&lt;/code&gt;, &lt;code&gt;CMD&lt;/code&gt;, and &lt;code&gt;ENTRYPOINT&lt;/code&gt;. It doesn’t affect the &lt;code&gt;VOLUME&lt;/code&gt; instruction;
if it did, you’d probably just get a permission denied error unless the user
you switch to had privileges to create mount points.&lt;/p&gt;
&lt;p&gt;OK, so instead we might try using the good old &lt;code&gt;chown&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;alpine&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;RUN&lt;/span&gt; adduser -D -u &lt;span class=&#34;chroma-m&#34;&gt;1113&lt;/span&gt; test123&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;VOLUME&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;/testing&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;RUN&lt;/span&gt; chown test123 /testing&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But again, the directory is just owned by root at runtime.
Back to the docs, this time for the
&lt;a href=&#34;https://docs.docker.com/engine/reference/builder/#volume&#34;&gt;&lt;code&gt;VOLUME&lt;/code&gt; instruction&lt;/a&gt;
and towards the bottom is this little tidbit:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Changing the volume from within the Dockerfile: If any build steps change
the data within the volume after it has been declared, those changes will
be discarded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As soon as Docker hits the &lt;code&gt;VOLUME&lt;/code&gt; instruction the directory becomes a mount
point, and anything we do to the temporary volume mounted there is discarded
during the build process. So we have to change the ownership &lt;em&gt;before&lt;/em&gt; the
instruction, which may seem a little counter-intuitive:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;alpine&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;RUN&lt;/span&gt; adduser -D -u &lt;span class=&#34;chroma-m&#34;&gt;1113&lt;/span&gt; test123&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;RUN&lt;/span&gt; mkdir /testing &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chown test123 /testing&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;VOLUME&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;/testing&lt;/span&gt;&lt;span class=&#34;chroma-err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now when the container runs, the /testing directory is owned by the test123
user. It’s not quite over, yet, though. This works if we let Docker create
a volume automatically for us, or if we create a named volume and mount that;
if we try and mount a host directory, though, it falls flat:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v &amp;#34;$PWD/testing:/testing&amp;#34; testing ls -al /testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 1000     1000          4096 Apr  1 19:39 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 root     root          4096 Apr  1 20:44 ..
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Docker handles mounting host directories differently to mounting volumes,
even though the syntax is basically the same. Host directories are bind
mounted directly into the container, so the permissions and ownership
are the same as the directory on your host. The only way to fix them are
to either change the permissions on the host, or have the container
change them at runtime (assuming it has sufficient privileges).&lt;/p&gt;
&lt;p&gt;One final wrinkle in all this happens when you use the same volume
in multiple containers. Here we have two images built from the
Dockerfile above, one with userid 1113 and one with userid 1114:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker volume create testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing1113 ls -nal /testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 1113     0             4096 Apr  1 19:49 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 0        0             4096 Apr  1 20:51 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing1114 ls -nal /testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 1114     0             4096 Apr  1 20:47 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 0        0             4096 Apr  1 20:52 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing1114 touch /testing/Hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing1113 ls -nal /testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 1114     0             4096 Apr  1 20:52 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 0        0             4096 Apr  1 20:53 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rw-r--r--    1 0        0                0 Apr  1 20:52 Hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing1114 ls -nal /testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 1114     0             4096 Apr  1 20:52 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 0        0             4096 Apr  1 20:52 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rw-r--r--    1 0        0                0 Apr  1 20:52 Hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can you see what’s going on? When the volume is empty, the ownership
changes based on the mount point in the container. Once it has something
in it, the ownership is fixed.&lt;/p&gt;
&lt;p&gt;So Docker behaves differently with regard to permissions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when the folder is mounted from the host vs a volume&lt;/li&gt;
&lt;li&gt;when the volume is empty vs having content&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;pre-populating-mounts-with-files-from-the-image&#34;&gt;Pre-populating mounts with files from the image&lt;/h3&gt;
&lt;p&gt;One of the more esoteric features of the way Docker handles volume
mounts is that in some cases files from the image are copied over
into the container. For example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker volume create testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/etc testing sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/tmp testing ls -al /tmp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 184
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x   15 root     root          4096 Apr  1 20:58 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 root     root          4096 Apr  1 20:59 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rw-r--r--    1 root     root             4 Jun  7  2018 TZ
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rw-r--r--    1 root     root             6 Dec 20 21:31 alpine-release
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first container we run mounts the newly created &lt;code&gt;testing&lt;/code&gt; volume
at &lt;code&gt;/etc&lt;/code&gt;. Docker copies all the existing files and folders into the
volume; when we then run the second container with the volume mounted
at &lt;code&gt;/tmp&lt;/code&gt;, we can see all the files that were in the first container’s
&lt;code&gt;/etc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As with permissions, this behaviour is anything but consistent. Say we
switch from a volume to a host directory:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ mkdir testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v &amp;#34;$PWD/testing:/usr/bin&amp;#34; testing sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ ls -al testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x 2 root  root  4096 Apr  1 22:05 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x 3 chris chris 4096 Apr  1 22:05 ..
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nothing is copied in, and inside the container the folder will be empty.
Based on our discoveries with permissions, it’s reasonable to assume the
same will happen with a non-empty volume too:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker volume create testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/testing testing touch /testing/Hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/usr/bin testing sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v testing:/tmp testing ls -al /tmp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    2 root     root          4096 Apr  1 21:09 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x    1 root     root          4096 Apr  1 21:09 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rw-r--r--    1 root     root             0 Apr  1 21:08 Hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So at least that’s consistent. If you’re very observant, though, you
might notice I switched from &lt;code&gt;/etc/&lt;/code&gt; to &lt;code&gt;/usr/bin&lt;/code&gt; in the examples.
That’s because within the container &lt;code&gt;/etc/&lt;/code&gt; has some files bind-mounted
into it, such as &lt;code&gt;/etc/resolv.conf&lt;/code&gt;, and these &lt;em&gt;do&lt;/em&gt; always result in files
being created in the mounted volumes or folders:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ mkdir testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it -v &amp;#34;$PWD/testing:/etc&amp;#34; testing sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ ls -al testing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;total 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x 2 chris chris 4096 Apr  1 22:12 .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;drwxr-xr-x 3 chris chris 4096 Apr  1 22:12 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rwxr-xr-x 1 root  root     0 Apr  1 22:12 hostname
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rwxr-xr-x 1 root  root     0 Apr  1 22:12 hosts
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;-rwxr-xr-x 1 root  root     0 Apr  1 22:12 resolv.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker treats mounting host folders and mounting volumes differently.
Don’t just assume that you can swap one for another and get the exact
same behaviour.&lt;/li&gt;
&lt;li&gt;Empty volumes will inherit permissions and files from the image
they are mounted in; non-empty volumes and host folders will not.&lt;/li&gt;
&lt;li&gt;Relying on Docker copying files into volumes is a very bad idea,
as if you change those files in a future version of your image
they will not be copied unless the volume is deleted and
recreated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can’t find anywhere that these points are documented properly;
if you know of anywhere, please drop me a message!&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Why you should be using HTTPS</title>
        <link href="https://chameth.com/why-you-should-be-using-https/"/>
        <updated>2016-06-17T00:00:00Z</updated>
        <id>https://chameth.com/why-you-should-be-using-https/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/why-you-should-be-using-https/https-everywhere.jpg&#34; alt=&#34;The EFF&amp;#39;s HTTPS Everywhere logo&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;260&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The EFF’s HTTPS Everywhere logo&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One of my favourite hobbyhorses recently has been the use of HTTPS, or lack thereof. HTTPS is the
thing that makes the little padlock appear in your browser, and has existed for over 20 years.
In the past, that little padlock was the exclusive preserve of banks and other ‘high security’
establishments; over time its use has gradually expanded to most (but not all) websites
that handle user information, and the time is now right for it to become ubiquitous.&lt;/p&gt;
&lt;h3 id=&#34;why-use-https&#34;&gt;Why use HTTPS?&lt;/h3&gt;
&lt;p&gt;There are numerous advantages to using HTTPS, both for the users of a website and for the
operator:&lt;/p&gt;
&lt;h4 id=&#34;privacy&#34;&gt;Privacy&lt;/h4&gt;
&lt;p&gt;The most obvious advantage is that HTTPS gives your users additional privacy. An insecure (HTTP)
request can potentially be read by anyone on the same network, or the network operators, or anyone
who happens to operate a network along the path between the user and the server.&lt;/p&gt;
&lt;p&gt;Users on shared WiFi networks (such as those in coffee shops, hotels, or offices) are particularly
vulnerable to passive sniffing by anyone else on that network. If the network is open (as is
frequently the case) then anyone in radio range can see exactly what the user is up to.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h4 id=&#34;integrity&#34;&gt;Integrity&lt;/h4&gt;
&lt;p&gt;HTTPS also helps to maintain the integrity of your site. With a plain HTTP request, there’s nothing
to stop anyone in between the server and the user from modifying the content of the request or the
response. This is a frequent tactic used by annoying WiFi gateways (such as the ones &lt;a href=&#34;http://justinsomnia.org/2012/04/hotel-wifi-javascript-injection/&#34;&gt;you’d find in
a hotel&lt;/a&gt;), dubious ISPs who want
to serve you extra adverts, or just plain old nefarious attackers.&lt;/p&gt;
&lt;p&gt;If you’re trying to convey some kind of information to users (and if you aren’t, why exactly are
you running a website again?) it seems beneficial to both you and them if the information arrives
as you intended, rather than in a modified form due to someone or something tampering with it.&lt;/p&gt;
&lt;h4 id=&#34;security&#34;&gt;Security&lt;/h4&gt;
&lt;p&gt;If your website has any kind of authentication, or session identifiers, it becomes extremely
vulnerable to an attacker monitoring the traffic and stealing the credentials. This was
starkly demonstrated in 2010 when &lt;a href=&#34;https://en.wikipedia.org/wiki/Firesheep&#34;&gt;Firesheep&lt;/a&gt; was
released. This tool allowed anyone to quickly and automatically hijack social media accounts of
anyone on the same network who was using HTTP to access them.&lt;/p&gt;
&lt;p&gt;Even if your login pages are served over HTTPS, if you send a single session ID cookie over HTTP
(such as a page you decided wasn’t particularly ‘important’) then an attacker can probably spoof
the user’s session and gain full access to their account.  Again, in the case of open WiFi networks
that could be anyone in radio range.&lt;/p&gt;
&lt;h4 id=&#34;search-engine-rankings&#34;&gt;Search engine rankings&lt;/h4&gt;
&lt;p&gt;Some search engines use HTTPS as a signal in their ranking algorithms. &lt;a href=&#34;https://security.googleblog.com/2014/08/https-as-ranking-signal_6.html&#34;&gt;Google announced in
2004&lt;/a&gt; that it was using
the presence of HTTPS as a small positive signal, but that it may strengthen that signal over time
as more and more websites switch to using a secure transport. It’s not unthinkable that at some
point in the future there will be HTTPS-only search engines.&lt;/p&gt;
&lt;h3 id=&#34;but-but-but&#34;&gt;But… But… But…&lt;/h3&gt;
&lt;p&gt;There are lots of excuses for not implementing HTTPS. Most of them are either misguided or outdated.&lt;/p&gt;
&lt;h4 id=&#34;its-too-expensive-andor-complicated&#34;&gt;It’s too expensive and/or complicated&lt;/h4&gt;
&lt;p&gt;In the past, getting HTTPS certificates was a pain. A number of free suppliers have existed for
a while but the process for getting their certificates wasn’t particularly straight forward, and
many imposed arbitrary restrictions on the certificate parameters. Even once you had the
certificate, you had to fiddle about with your HTTP server configuration to make it work, remember
to manually get a new certificate when the old one expired, and lots of other annoying busywork.&lt;/p&gt;
&lt;p&gt;With the arrival of &lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Let’s Encrypt&lt;/a&gt;, all that changed. You can retrieve
and deploy a free HTTPS certificate with two or three commands. Renewal can be handled completely
automatically with a single command executed by cron.&lt;/p&gt;
&lt;h4 id=&#34;theres-no-point-nothing-on-my-site-is-sensitive&#34;&gt;There’s no point; nothing on my site is sensitive&lt;/h4&gt;
&lt;p&gt;You might not think your content warrants privacy, but can you speak for everyone who accesses it?
Even content that seems mundane to you — such as travel advice, or technical writing — could be
used to build up a profile of a user. If an attacker is monitoring traffic in a coffee shop and
sees a user looking at travel advice and weather forecasts for a foreign country, he could use that
information to plan a burglary knowing that the user will be away. Similarly, some content which
is perfectly mundane to you may actually be very sensitive in other countries with repressive
governments. HTTPS makes it much harder for these people to snoop on traffic.&lt;/p&gt;
&lt;p&gt;From another angle, if you’re offering any kind of information, instructions, or especially file
downloads, there’s a severe risk to users if the content is modified on its way to them. An evil
sysadmin could rewrite your travel advice to suggest visiting the local drug dealer’s hangout, or
replace your download with a malware-infested version.&lt;/p&gt;
&lt;h4 id=&#34;https-is-slower-uses-more-resources-etc&#34;&gt;HTTPS is slower, uses more resources, etc&lt;/h4&gt;
&lt;p&gt;Back in 1995 this might have been a valid argument. Enabling HTTPS on a modern server will make
an almost negligible difference to performance. If you also enable HTTP/2 (which most
implementations only support over HTTPS), it’s likely to actually use fewer resources, and result
in a faster, smoother experience for your users. HTTP/2 was designed to work with HTTPS, and
designed with modern requirements and networking techniques in mind.&lt;/p&gt;
&lt;p&gt;CloudFlare have an &lt;a href=&#34;https://www.cloudflare.com/http2/&#34;&gt;excellent demonstration&lt;/a&gt; of the benefits of
HTTP/2, and it can show speed improvements of 2-3x in a typical environment. On top of being faster,
HTTP/2 uses fewer connections which results in less resource overhead on both the server and the
client.&lt;/p&gt;
&lt;h3 id=&#34;so-what-are-you-waiting-for&#34;&gt;So what are you waiting for?&lt;/h3&gt;
&lt;p&gt;If you run a website and aren’t using HTTPS, &lt;a href=&#34;https://certbot.eff.org/&#34;&gt;give it a try&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
</feed>
