<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>my tech blog &#187; Server admin</title>
	<atom:link href="http://billauer.co.il/blog/category/server-admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://billauer.co.il/blog</link>
	<description>Anything I found worthy to write down.</description>
	<lastBuildDate>Sun, 19 Sep 2021 10:43:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Using firejail to throttle network bandwidth for wget and such</title>
		<link>http://billauer.co.il/blog/2021/08/firejail-network-bandwidth-limit/</link>
		<comments>http://billauer.co.il/blog/2021/08/firejail-network-bandwidth-limit/#comments</comments>
		<pubDate>Sun, 15 Aug 2021 13:39:17 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>
		<category><![CDATA[Virtualization]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6382</guid>
		<description><![CDATA[Introduction Occasionally, I download / upload huge files, and it kills my internet connection for plain browsing. I don&#8217;t want to halt the download or suspend it, but merely calm it down a bit, temporarily, for doing other stuff. And then let it hog as much as it want again. There are many ways to [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Occasionally, I download / upload huge files, and it kills my internet connection for plain browsing. I don&#8217;t want to halt the download or suspend it, but merely calm it down a bit, temporarily, for doing other stuff. And then let it hog as much as it want again.</p>
<p>There are many ways to do this, and I went for firejail. I suggest reading <a title="Firejail: Putting a program in its own little container" href="http://billauer.co.il/blog/2020/06/firejail-cgroups/" target="_blank">this post of mine</a> as well on this tool.</p>
<p>Firejail gives you a shell prompt, which runs inside a mini-container, like those cheap virtual hosting services. Then run wget or youtube-dl as you wish from that shell.</p>
<p>It has practically access to everything on the computer, but the network interface is controlled. Since firejail is based on cgroups, all processes and subprocesses are collectively subject to the network bandwidth limit.</p>
<p>Using firejail requires setting up a bridge network interface. This is a bit of container hocus-pocus, and is necessary to get control  over the network data flow. But it&#8217;s simple, and it can be done once  (until the next reboot, unless the bridge is configured permanently,  something I don&#8217;t bother).</p>
<h3>Setting up a bridge interface</h3>
<p>Remember: Do this once, and just don&#8217;t remove the interface when done with it.</p>
<p>You might need to</p>
<pre># <strong>apt install bridge-utils</strong></pre>
<p>So first, set up a new bridge device (as root):</p>
<pre># <strong>brctl addbr hog0</strong></pre>
<p>and give it an IP address that doesn&#8217;t collide with anything else on the system. Otherwise, it really doesn&#8217;t matter which:</p>
<pre># <strong>ifconfig hog0 10.22.1.1/24</strong></pre>
<p>What&#8217;s going to happen is that there will be a network interface named eth0 inside the container, which will behave as if it was connected to a real Ethernet card named hog0 on the computer. Hence the container has access to everything that is covered by the routing table (by means of IP forwarding), and is also subject to the firewall rules. With my specific firewall setting, it prevents some access, but ppp0 isn&#8217;t blocked, so who cares.</p>
<p>To remove the bridge (no real reason to do it):</p>
<pre># <strong>brctl delbr hog0</strong></pre>
<h3>Running the container</h3>
<p>Launch a shell with firejail (I called it &#8220;nethog&#8221; in this example):</p>
<pre>$ <strong>firejail --net=hog0 --noprofile --name=nethog</strong></pre>
<p>This starts a new shell, for which the bandwidth limit is applied. Run wget or whatever from here.</p>
<p>Note that despite the &#8211;noprofile flag, there are still some directories that are read-only and some are temporary as well. It&#8217;s done in a sensible way, though so odds are that it won&#8217;t cause any issues. Running &#8220;df&#8221; inside the container gives an idea on what is mounted how, and it&#8217;s scarier than the actual situation.</p>
<p>But <strong>be sure to check that the files that are downloaded are visible outside the container</strong>.</p>
<p>From another shell prompt, <strong>outside the container</strong> go something like (<strong>doesn&#8217;t </strong>require root):</p>
<pre>$ <strong>firejail --bandwidth=nethog set hog0 800 75</strong>
Removing bandwith limit
Configuring interface eth0
Download speed  6400kbps
Upload speed  600kbps
cleaning limits
configuring tc ingress
configuring tc egress
</pre>
<p>To drop the bandwidth limit:</p>
<pre>$ <strong>firejail --bandwidth=nethog clear hog0</strong></pre>
<p>And get the status (saying, among others, how many packets have been dropped):</p>
<pre>$ <strong>firejail --bandwidth=nethog status</strong></pre>
<p>Notes:</p>
<ul>
<li>The &#8220;eth0&#8243; mentioned in firejail&#8217;s output blob relates to the interface name <strong>inside</strong> the container. So the &#8220;real&#8221; eth0 remains untouched.</li>
<li>Actual download speed is slightly slower.</li>
<li>The existing group can be joined by new processes with firejail &#8211;join, as well as from firetools.</li>
<li>Several containers may use the same bridge (hog0 in the example  above), in which case each has its own independent bandwidth setting.  Note that the commands configuring the bandwidth limits mention both the  container&#8217;s name and the bridge.</li>
</ul>
<h3>Working with browsers</h3>
<p>When starting a browser from within a container, pay attention to  whether it really started a new process. Using firetools can help.</p>
<p>If  Google Chrome says &#8220;Created new window in existing browser session&#8221;, it <strong>didn&#8217;t</strong> start a new process inside the container, in which case the window isn&#8217;t subject to bandwidth limitation.</p>
<p>So close all windows of Chrome before kicking off a new one. Alternatively, this can we worked around by starting the container with.</p>
<pre>$ firejail --net=hog0 --noprofile <strong>--private</strong> --name=nethog</pre>
<p>The &#8211;private flags creates, among others, a new <strong>volatile</strong> home directory, so Chrome doesn&#8217;t detect that it&#8217;s already running. Because I use some other disk mounts for the large partitions on my computer, it&#8217;s still possible to download stuff to them from within the container.</p>
<p>But extra care is required with this, and regardless, the new browser doesn&#8217;t remember passwords and such from the private container.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2021/08/firejail-network-bandwidth-limit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When dovecot silently stops to deliver mails</title>
		<link>http://billauer.co.il/blog/2021/07/dovecot-fetchmail-pop3-stuck/</link>
		<comments>http://billauer.co.il/blog/2021/07/dovecot-fetchmail-pop3-stuck/#comments</comments>
		<pubDate>Fri, 23 Jul 2021 09:30:14 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[email]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6369</guid>
		<description><![CDATA[After a few days being happy with not getting spam, I started to suspect that something is completely wrong with receiving mail. As I&#8217;m using fetchmail to get mail from my own server running dovecot v2.2.13, I&#8217;m used to getting notifications when fetchmail is unhappy. But there was no such. Checking up the server&#8217;s logs, [...]]]></description>
			<content:encoded><![CDATA[<p>After a few days being happy with not getting spam, I started to suspect that something is completely wrong with receiving mail. As I&#8217;m using fetchmail to get mail from my own server running dovecot v2.2.13, I&#8217;m used to getting notifications when fetchmail is unhappy. But there was no such.</p>
<p>Checking up the server&#8217;s logs, there were tons of these messages:</p>
<pre>dovecot: master: Warning: service(pop3-login): process_limit (100) reached, client connections are being dropped</pre>
<p>Restarting dovecot got it back running properly again, and I got a flood of the mails that were pending on the server. This was exceptionally nasty, because mails stopped arriving silently.</p>
<p>So what was the problem? The clue is in these log messages, which occurred about a minute after the system&#8217;s boot (it&#8217;s a VPS virtual machine):</p>
<pre>Jul 13 11:21:46 dovecot: master: Error: service(anvil): Initial status notification not received in 30 seconds, killing the process
Jul 13 11:21:46 dovecot: master: Error: service(log): Initial status notification not received in 30 seconds, killing the process
Jul 13 11:21:46 dovecot: master: Error: service(ssl-params): Initial status notification not received in 30 seconds, killing the process
Jul 13 11:21:46 dovecot: master: Error: service(log): child 1210 killed with signal 9</pre>
<p>These three services are helper processes for dovecot, as can be seen in the output of systemctl status:</p>
<pre>            ├─dovecot.service
             │ ├─11690 /usr/sbin/dovecot -F
             │ ├─11693 dovecot/anvil
             │ ├─11694 dovecot/log
             │ ├─26494 dovecot/config
             │ ├─26495 dovecot/auth
             │ └─26530 dovecot/auth -w</pre>
<p>What seems to have happened is that these processes failed to launch properly within the 30 second timeout limit, and were therefore killed by dovecot. And then attempts to make pop3 connections seem to have got stuck, with the forked processes that are made for each connection remaining. Eventually, they reached the maximum of 100.</p>
<p>The reason this happened only now is probably that the hosting server had some technical failure and was brought down for maintenance. When it went up again, all VMs were booted at the same time, so they were all very slow in the beginning. Hence it took exceptionally long to kick off those helper processes. The 30 seconds timeout kicked in.</p>
<p>The solution? Restart dovecot once in 24 hours with a plain cronjob. Ugly, but works. In the worst case, mail will be delayed for 24 hours. This is a very rare event to begin with.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2021/07/dovecot-fetchmail-pop3-stuck/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A sledge hammer introduction to X.509 certificates</title>
		<link>http://billauer.co.il/blog/2021/04/certificate-ca-tutorial-primer/</link>
		<comments>http://billauer.co.il/blog/2021/04/certificate-ca-tutorial-primer/#comments</comments>
		<pubDate>Fri, 30 Apr 2021 16:20:35 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[crypto]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6269</guid>
		<description><![CDATA[Introduction First and foremost: Crypto is not my expertise. This is a note to future self for the next time I&#8217;ll need to deal with similar topics. This post summarizes my understanding as I prepared worked on a timestamp server, and it shows the certificates used by it. There are many guides to X.509 certificates [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>First and foremost: Crypto is not my expertise. This is a note to future self for the next time I&#8217;ll need to deal with similar topics. This post summarizes my understanding as I prepared worked on a timestamp server, and it shows the certificates used by it.</p>
<p>There are many guides to X.509 certificates out there, however it seems like it&#8217;s common practice to focus on the bureaucratic aspects (a.k.a. Public Key Infrastructure, or PKI), and less on the real heroes of this story: The public cryptographic keys that are being certified.</p>
<p>For example, <a href="https://tools.ietf.org/html/rfc3647" target="_blank">RFC 3647</a> starts with:</p>
<blockquote><p>In general, a public-key certificate (hereinafter &#8220;certificate&#8221;) binds a public key held by an entity (such as person, organization, account, device, or site) to a set of information that identifies the entity associated with use of the corresponding private key.  In most cases involving identity certificates, this entity is known as the &#8220;subject&#8221; or &#8220;subscriber&#8221; of the certificate.</p></blockquote>
<p>Which is surely correct, and yet it dives right into organization structures etc. Not complaining, the specific RFC is just about that.</p>
<p>So this post is an attempt to make friends with these small chunks of data, with a down-to-earth, technical approach. I&#8217;m not trying to cover all aspects nor being completely accurate. For exact information, refer to <a href="https://tools.ietf.org/html/rfc5280" target="_blank">RFC 5280</a>. When I say &#8220;the spec&#8221; below, I mean this document.</p>
<p>Let&#8217;s start from the basics, with the main character of this story: The digital signature.</p>
<p>The common way to make a digital signature  is to first produce a pair of cryptographic keys: One is secret, and the  second is public. Both are just short computer files.</p>
<p>The secret key is used in the mathematical operation that constitutes  the action of a digital signature. Having access to it is therefore  equivalent to being the person or entity that it represents. The public  key allows verifying the digital signature with a similar mathematical  operation.</p>
<p>A certificate is a message (practically &#8212; a computer file), saying &#8220;here&#8217;s a public key, and I hereby certify that it&#8217;s valid for use between this and this time for these and these uses&#8221;. This message is then digitally signed by whoever gives the certification (with is a key different from the one certified, of course). As we shall see below, there&#8217;s a lot more information in a certificate, but this is the point of it all.</p>
<p>The purpose of a certificate is like ID cards in real life: It&#8217;s a document that allows us to trust a piece of information from someone we&#8217;ve never seen before and know nothing about, without the possibility to consult with a third party. So there must be something about this document that makes it trustworthy.</p>
<h3>The certificate chain</h3>
<p>Every piece of software that works with public keys is installed with a list of public keys that it trusts. Browsers carry a relatively massive list for SSL certificates, but for kernel code signing it consists of exactly one certificate. So the size of this list varies, but is surely very small compared with the number of certificates out there are in general. Keys may be added and removed to this list in the course of time, but its size remains roughly the same.</p>
<p>The common way to maintain this list is by virtue of root certificates: These certificates basically say &#8220;trust me, this key is OK&#8221;. I&#8217;ll get further into this along with the example of a root certificate below.</p>
<p>As the secret keys of these root certificates are precious, they can&#8217;t be used to sign every certificate in the world. Instead, these are used to approve the key of another certificate. And quite often, that second certificate approves the key for verifying a third certificate. Only that certificate approves the public key which the software needs to know if it&#8217;s OK for use. In this example, these three certificates form a <strong>certificate chain</strong>. In real life, this chain usually consists of 3-5 certificates.</p>
<p>In many practical applications (e.g. code signing and time stamping) the sender of the data for validation also attaches a few certificates in order to help the validating side. Likewise, when a browser establishes a secure connection, it typically receives more than one certificate.</p>
<p>None of these peer-supplied certificates are root certificates (and if there is one, any sane software will ignore it, or else is the validation worthless). The validating software then attempts to create a valid certificate chain going from its own pool of root certificates (and possibly some other certificates it has access to) to the public key that needs validation. If such is found, the validation is deemed successful.</p>
<p>The design of the certificate system envisions two kinds of keys: Those used by <strong>End Entities</strong> for doing something useful, and those used by <strong>Certificate Authorities</strong> only for the purpose of signing and verifying other certificates. Each certificate testifies which type it belongs to in the &#8220;Basic Constraints&#8221; extension, as explained below.</p>
<p>Put shortly: The certificates that we (may) pay a company to make for us, are all End Entities certificates.</p>
<p>In this post I&#8217;ll show a valid certificate chain consisting of three certificates.</p>
<h3>A sample End Entity certificate</h3>
<p>This is a textual dump of a certificate, obtained with something like:</p>
<pre>openssl x509 -in thecertificate.crt -text</pre>
<p>Other tools represent the information slightly differently, but the terminology tends to remain the same.</p>
<pre>Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            65:46:72:11:63:f1:85:b4:3d:95:3d:72:66:e6:ee:c5:1c:f6:2b:6e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Time Stamping CA
        Validity
            Not Before: Jan  1 00:00:00 2001 GMT
            Not After : May 19 00:00:00 2028 GMT
        Subject: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Time Stamping Service CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:d7:34:07:c5:dd:f5:e6:6a:b2:9e:e6:76:e3:ce:
                    af:33:a3:10:60:97:e8:27:f1:62:87:90:a9:21:52:
<span style="color: #888888;"><em>[ ... ]</em></span>
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: critical
                Time Stamping
            X509v3 Subject Key Identifier:
                3A:E5:43:A1:40:3F:A4:0F:01:CE:D3:3F:2A:EE:4E:92:B9:28:5C:3A
            X509v3 Authority Key Identifier:
                keyid:3C:F5:43:45:3B:40:10:BC:3F:25:47:18:10:C4:19:18:83:8C:09:D0
                DirName:/C=GB/ST=Gallifrey/L=Gallifrey/O=Dr Who/CN=Dr Who Root CA
                serial:7A:CF:23:8D:2E:A7:6C:84:52:53:AF:BA:D7:26:7F:54:53:B2:2D:6B

    Signature Algorithm: sha256WithRSAEncryption
         6c:54:88:55:ff:c7:e1:81:73:4e:00:80:46:0d:dc:d9:32:c1:
         53:ba:ff:f9:32:e4:f3:83:c2:29:bb:e5:91:88:8e:6f:46:f4:
<span style="color: #888888;"><em>[ ... ]</em></span></pre>
<h3>The key owning the certificate</h3>
<p>Much of the difficulty to understand certificates stems from the fact that the bureaucratic terminology is misleading, making it look as if it was persons or companies that are certified.</p>
<p>So let&#8217;s keep the eyes on the ball: This is all about the cryptographic keys. There&#8217;s the key which is included in the certificate (the Subject&#8217;s public key) and there&#8217;s the key that signs the certificate (the Authority&#8217;s key). There are of course someones owning these keys, and their information is the one that is presented to us humans first and foremost. And yet, it&#8217;s all about the keys.</p>
<p>The certificate&#8217;s purpose is to say something about the cryptographic key which is given explicitly in the certificate&#8217;s body (printed out in hex format as &#8220;Modulus&#8221; above). On top of that, there&#8217;s always the <strong>&#8220;Subject&#8221;</strong> part, which the human-readable name given to this key.</p>
<p>As seen in the printout above, the Subject is a set of attributes and values assignments. Collectively, they are the name of the key. Which attributes are assigned differs from certificate to certificate, and it may even contain no attributes at all. The meaning of and rules for setting these has to do with the bureaucracy of assigning real-life certificates. From a technical point of view, these are just string assignments.</p>
<p>Usually, the most interesting one is CN, which stands for commonName, and is the most descriptive part in the Subject. And yet, it may be confusingly similar to that of other certificates.</p>
<p>For certificates which certify an SSL key for use by web server, the Subject&#8217;s CN is the domain it covers (possibly with a &#8220;*&#8221; wildcard). It might be the only assignment. For example *.facebook.com or mysmallersite.com.</p>
<p>Except for some root certificates, there&#8217;s a X509v3 <strong>Subject Key Identifier</strong> entry in the certificate as well. It&#8217;s a short hex string which is typically the SHA1 hash of the public key, or part of it, but the spec allows using other algorithms. It&#8217;s extremely useful for identifying certificates, since it&#8217;s easy to get confused between Subject names.</p>
<p>I&#8217;ll discuss root authorities and root certificates below, along with looking at a root certificate.</p>
<h3>The key that signed the certificate</h3>
<p>Then we have the &#8220;Authority&#8221; side, which is the collective name for whoever signed the certificate. Often called Certificate Authority, or CA for short. Confusingly enough (for me), it appears before the Subject, in the binary blob of the certificate as well as the text output above.</p>
<p>The bureaucratic name of this Authority is given as the&#8221;<strong>Issuer</strong>&#8220;. Once again, it consists of a set of attributes and values assignments, which collectively are the name of the key that is used to sign the certificate. This tells us to look for a certificate with an exact match: The exact same set of assignments, with the exact same values. If such issuer certificate is found, and we trust it, and it&#8217;s allowed to sign certificates, and the Issuer&#8217;s public key validates the signature of the Subject&#8217;s certificate &#8212; plus a bunch of other conditions &#8212; then the Subject certificate is considered valid. In other words, the public key it contains is valid for the uses mentioned in it. This said with lots of fine details omitted.</p>
<p>But looking for a certificate in the database based upon the name is inefficient, as the same entity may have multiple keys and hence multiple certificates for various reasons &#8212; in particular because a certificate is time limited. To solve this, all certificates (except root certificates) must point at their Authority with the X509v3 <strong>Authority Key Identifier</strong> field (though I&#8217;ve seen certificates without it). There are two methods for this:</p>
<ol>
<li>The value of that appears in the Subject Key Identifier field, in the certificate for the key that signed the current certificate (so it&#8217;s basically a hash of the public key that signed this certificate).</li>
<li>The serial number of the certificate of the key that signed the current certificate, plus the Issuer name of the Authority&#8217;s certificate &#8212; that is the Authority that is two levels up in the foodchain. This is a more heavy-weight identification, and gives us a hint on what&#8217;s going on higher up.</li>
</ol>
<p>The first method is more common (and is required if you want to call yourself a CA), and sometimes both are present.</p>
<p>Anyhow, practically speaking, when I want to figure out which certificate approves which, I go by the Subject / Authority Key Identifiers. It&#8217;s much easier to keep track of the first couple of hex octets than those typically long and confusing names.</p>
<h3>Validity times and Certificate serial number</h3>
<p>These are quite obvious: The validity time limits the time period for which the certificate can be used. The validating software uses the computer&#8217;s clock for this purpose, unless the validated message is timestamped (in particular with code signing), in which case the timestamp is used to validate all certificates in the chain.</p>
<p>The serial number is just a number that is unique for each certificate. The spec doesn&#8217;t define any specific algorithm for generating it. Note that this number relates to the certificate itself, and not to the public key being certified.</p>
<h3>The signature</h3>
<p>All certificates are signed with the secret key of their Authority. The public key for verifying it is given in the Authority&#8217;s certificate.</p>
<p>The signature algorithm appears at the beginning of the certificate, however the signature itself is last. The spec requires, obviously, that the algorithm that is used in the signature is the one stated in the beginning.</p>
<p>The signature is made on the ASN.1 DER-encoded blob which contains all certificate information (except for the signature section itself, of course).</p>
<h3>X509v3 extensions</h3>
<p>Practically all certificates that are used today are version 3 certificates, and they all have a section called X509v3 extensions. In this section, the creator of the certificate insert data objects as desired (but with some minimal requirements, as defined in the spec). The meaning and structure of each data object is conveyed by an Object Identifier (OID) field at the header of each object, appearing before the data in the certificate&#8217;s ASN.1 DER blob. It&#8217;s therefore possible to push any kind of data in this section, by assigning an OID for that kind of data.</p>
<p>In addition to the OID, each such data object also has a boolean value called &#8220;critical&#8221;: Note that some of the extensions in the example above are marked as critical, and some are not. When an extension is critical (the boolean is set true) the certificate must be deemed invalid if the extension is not recognized by its verifying software. Extensions that limit the usage of a certificate are typically marked critical, so that unintended use doesn&#8217;t occur because the extension wasn&#8217;t recognized.</p>
<p>I&#8217;ve already mentioned two x509v3 extensions: X509v3 Subject Key Identifier and X509v3 Authority Key Identifier, none of which are critical in the example above. And it makes sense: If the verifying software doesn&#8217;t recognize these, it has other means to figure out which certificate goes where.</p>
<p>So coming up next is a closer look at a few standard X509v3 extensions.</p>
<h3>X509v3 Key Usage</h3>
<p>As its name implies, this extension defines the allowed uses of the key contained in the certificate. A certificate that is issued by a CA must have this extension present, and mark it Critical.</p>
<p>This extension contains a bit string of 8 bits, defining the allowed usages as follows:</p>
<ul>
<li>Bit 0: digitalSignature &#8212; verify a digital signature other than the one of a certificate or <a href="https://en.wikipedia.org/wiki/Certificate_revocation_list" target="_blank">CRL</a> (these are covered with bits 5 and 6).</li>
<li>Bit 1: nonRepudiation (or contentCommitment) &#8212; verify a digital signature in a way that is legally binding. In other words, a signature made with this key can&#8217;t be claimed later to be false.</li>
<li>Bit 2: keyEncipherment &#8212; encipher a private or secret key with the <strong>public key</strong> contained in the certificate.</li>
<li>Bit 3: dataEncipherment &#8212; encipher payload data directly with the public key (rarely used).</li>
<li>Bit 4: keyAgreement &#8212; for use with Diffie-Hellman or similar key exchange methods.</li>
<li>Bit 5:  keyCertSign &#8212; verify the digital signature of certificates.</li>
<li>Bit 6: cRLSign &#8212; verify the digital signature of <a href="https://en.wikipedia.org/wiki/Certificate_revocation_list" target="_blank">CRL</a>s.</li>
<li>Bit 7: encipherOnly &#8212; when this and keyAgreement bits are set,  only enciphering data is allowed in the key exchange process.</li>
<li>Bit 8:  decipherOnly &#8212; when this and keyAgreement bits are set,  only deciphering data is allowed in the key exchange process.</li>
</ul>
<h3>X509v3 Extended Key Usage</h3>
<p>The Key Usage extension is somewhat vague about the purposes of the cryptographic operations. In particular, when the public key can be used to verify digital signature, surely not all kinds of signatures? If this was the case, this would make the public key valid to sign anything (that isn&#8217;t a legal document, a certificate and a CRL, and still).</p>
<p>On the other hand, how can a protocol properly foresee any possible use of the public key? Well, it can&#8217;t. Instead, each practical use of the key is given a unique number in the vocabulary of Object Identifiers (OIDs). This extension merely lists the OIDs that are relevant, and this translates into allowed uses. When evaluating the eligibility to use the public key (that is contained in the certificate), the Key Usage and Extended Key Usage are evaluated separately; a green light is given only if both evaluations resulted in an approval.</p>
<p>The spec doesn&#8217;t require this extension to be marked Critical, but it usually is, or what&#8217;s the point. The spec does however say that &#8220;in general, this extension will appear only in end entity certificates&#8221;, i.e. a certificate that is given to the end user (and hence with a key that can&#8217;t be used to sign other certificates). In reality, this extension is often present and assigned the intended use in certificates in the middle of the chain, despite this suggestion. As I&#8217;ve seen this in code signing and time stamping middle-chain certificates, maybe it&#8217;s to restrict the usage of this middle certificate for certain purposes. Or maybe it&#8217;s a workaround for buggy validation software.</p>
<p>This is a short and incomplete list of interesting OIDs that may appear in this extension:</p>
<ul>
<li>TLS Web Server Authentication: 1.3.6.1.5.5.7.3.1</li>
<li>TLS Web Client Authentication: 1.3.6.1.5.5.7.3.2</li>
<li>Code signing: 1.3.6.1.5.5.7.3.3</li>
<li>Time stamping: 1.3.6.1.5.5.7.3.8</li>
</ul>
<p>The first two appear in certificates that are issued for HTTPS servers.</p>
<h3>X509v3 Basic Constraints</h3>
<p>Never mind this extension&#8217;s name. It has nothing to do with what it means.</p>
<p>This extension involves two elements: First, a boolean value, &#8220;cA&#8221;, meaning Certificate Authority. According to the spec, the meaning of this flag is that the Subject of the certificate is a Certificate Authority (as opposed to End Entity). When true, the key included in the certificate may be used to sign other certificates.</p>
<p>But wait, what about the keyCertSign capability in X509v3 Key Usage (i.e. bit 6)? Why the duplicity? Not clear, but the spec requires that if cA is false, then keyCertSign must be cleared (certification signature not allowed). In other words, if you&#8217;re not a CA, don&#8217;t create certificates that can sign other certificates.</p>
<p>This flag is actually useful for manually analyzing a certificate chain going from the end user certificate towards the root: Given a pile of certificates, look for the one with CA:FALSE. That&#8217;s the certificate to start with.</p>
<p>The second element is pathLenConstraint, which usually appears as pathlen in text dumps. It limits the number of certificates between the current one and the final certificate in the chain, which is typically the End Entity certificate. Commonly, pathlen is set to zero in the certificate that authorizes the certificate that someone paid to get.</p>
<p>If there&#8217;s a self-issued certificate (Subject is identical to Issuer) in the chain which isn&#8217;t the root certificate, forget what I said about pathlen. But first find me such a certificate.</p>
<p>This extension is allowed to be marked critical or not.</p>
<h3>X509v3 Subject Alternative Name</h3>
<p><em>(not in the example above)</em></p>
<p>This extension allows assigning additional names, on top of the one appearing in Subject (or possibly instead of it). It&#8217;s often used with SSL certificates in order to make it valid for multiple domains.</p>
<h3>A sample non-root CA certificate</h3>
<p>This is the text dump of the certificate which is the Authority of the example certificate listed above:</p>
<pre>Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            7a:cf:23:8d:2e:a7:6c:84:52:53:af:ba:d7:26:7f:54:53:b2:2d:6b
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Root CA
        Validity
            Not Before: Jan  1 00:00:00 2001 GMT
            Not After : May 19 00:00:00 2028 GMT
        Subject: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Time Stamping CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b6:bf:46:38:c7:c1:63:58:f1:95:c6:cf:0a:5d:
                    72:d1:11:ce:86:96:04:ce:8f:cb:ab:da:22:b9:e0:
<span style="color: #888888;"><em>[ ... ]</em></span>
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Extended Key Usage:
                Time Stamping
            X509v3 Subject Key Identifier:
                3C:F5:43:45:3B:40:10:BC:3F:25:47:18:10:C4:19:18:83:8C:09:D0
            X509v3 Authority Key Identifier:
                keyid:98:9A:E3:EF:D8:C5:5C:7F:87:35:87:45:78:3D:51:8D:82:2F:1E:A3
                DirName:/C=GB/ST=Gallifrey/L=Gallifrey/O=Dr Who/CN=Dr Who Root CA
                serial:03:91:DC:F3:FA:8D:5A:CA:D0:3D:B7:EE:1B:71:2D:60:B5:0A:99:DE

    Signature Algorithm: sha256WithRSAEncryption
         13:18:16:99:6a:42:be:22:14:e5:e8:80:5a:ce:be:df:33:c6:
         22:df:d5:35:48:e6:9d:9f:ec:ec:07:72:49:33:ca:ca:3f:22:
<em><span style="color: #888888;">[ ... ]</span></em></pre>
<p>The public key contained in this certificate is pair with the secret key that signed the certificate before. As one would expect, this following fields match:</p>
<ul>
<li>The list of assignments in Subject of this certificate is exactly the same as the Issuer in the previous one.</li>
<li>The Subject Key Identifier here with Authority Key Identifier, as keyid, in the previous one.</li>
<li>This Certificate&#8217;s Serial number appears in Authority Key Identifier as serial.</li>
<li>This Certificate&#8217;s Issuer appears in Authority Key Identifier in a condensed form as DirName.</li>
</ul>
<p>Except for the Subject to Issuer match, the other fields may be missing in certificates. There&#8217;s a brief description of how the certificate chain is validated below, after showing the root certificate. At this point, these relations are listed just to help figuring out which certificate certifies which.</p>
<p>Note that unlike the previous certificate, CA is TRUE, which means that this a CA certificate (as opposed to End Entities certificate). In other words, it&#8217;s intended for the sole use of signing other certificates (and it does, at least the one above).</p>
<p>Also note that pathlen is assigned zero. This means that the it&#8217;s used only to sign End Entity certificates.</p>
<p>Note that DirName in Authority Key Identifier equals this certificate&#8217;s Issuer. Recall that DirName is the Issuer of the certificate that certifies this one. Hence the conclusion is that the certificate that certifies this one has the same name for Subject and Issuer: So with this subtle clue, we know almost for sure that the certificate above this one is a root certificate. Why almost? Because non-root self-issued certificates are allowed in the spec, but kindly show me one.</p>
<p>Extended Key Usage is set to Time Stamping. Even though this was supposed to be unusual, as mentioned before, this is what non-root certificates for time stamping and code signing usually look like.</p>
<p>And as expected, the Key Usage is Certificate Sign and CRL Sign, as one would expect to find on a CA certificate.</p>
<h3>A sample root CA certificate</h3>
<p>And now we&#8217;re left with the holy grail: the root certificate.</p>
<pre>Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            03:91:dc:f3:fa:8d:5a:ca:d0:3d:b7:ee:1b:71:2d:60:b5:0a:99:de
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Root CA
        Validity
            Not Before: Jan  1 00:00:00 2001 GMT
            Not After : May 19 00:00:00 2028 GMT
        Subject: C = GB, ST = Gallifrey, L = Gallifrey, O = Dr Who, CN = Dr Who Root CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:ce:e5:53:d7:1e:43:28:13:00:eb:b2:81:bb:ff:
                    28:23:98:9a:fd:69:07:ee:49:c5:54:44:66:77:5d:
<span style="color: #888888;"><em>[ ... ]</em></span>
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                98:9A:E3:EF:D8:C5:5C:7F:87:35:87:45:78:3D:51:8D:82:2F:1E:A3
            X509v3 Authority Key Identifier:
                keyid:98:9A:E3:EF:D8:C5:5C:7F:87:35:87:45:78:3D:51:8D:82:2F:1E:A3
                DirName:/C=GB/ST=Gallifrey/L=Gallifrey/O=Dr Who/CN=Dr Who Root CA
                serial:03:91:DC:F3:FA:8D:5A:CA:D0:3D:B7:EE:1B:71:2D:60:B5:0A:99:DE

            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
    Signature Algorithm: sha256WithRSAEncryption
         30:92:7d:09:e4:ea:4d:81:dd:8e:c2:ba:c0:c4:a6:26:62:4d:
<span style="color: #888888;"><em>[ ... ]</em></span></pre>
<p>All in all, it&#8217;s pretty similar to the previous non-root certificate, except that its Authority is itself: There is no way to validate this certificate, as there is no other public key to use. As mentioned above, root certificates are installed directly into the validating software&#8217;s database as the anchors of trust.</p>
<p>The list of fields that match between this and the previous certificate remains the same as between the previous certificate and its predecessor. Once again, not all fields are always present. Actually, there are a few fields that make no sense in a root certificate, and yet they are most commonly present. Let&#8217;s look at a couple of oddities (that are common):</p>
<ul>
<li>The certificate is signed. One may wonder what for. The signature is always done with the Authority&#8217;s key, but in this case, its the key contained in the certificate itself. So this proves that the issuer of this certificate has the secret key that corresponds to the public key that is contained in the certificate. The need for a signature hence prevents issuing a root certificate for a public key without being the owner of the secret key. Why anyone would want to do that remains a question.</li>
<li>The certificate points at itself in the Authority Key Identifier extension. This is actually useful for spotting that this is indeed a root certificate, in particular when there are long and rambling names in the Subject / Issuer fields. But why the DirName?</li>
</ul>
<h3>How the certificate chain is validated</h3>
<p>Chapter 6 of <a href="https://tools.ietf.org/html/rfc5280" target="_blank">RFC 5280</a> offers a 20 pages long description of how a certificate chain is validated, and it&#8217;s no fun to read. However section 6.1.3 (&#8220;Basic Certificate Processing&#8221;) gives a concise outline of how the algorithm validates certificate Y based upon certificate X.</p>
<p>The algorithm given in the spec assumes that some other algorithm has found a candidate for a  certificate chain. Chapter 6 describes how to check it by starting from  root, and advancing one certificate pair at a time. This direction isn&#8217;t intuitive, as validation software usually encounters an End Entities certificate, and needs to figure out how to get to root from it. But as just said, the assumption is that we already know.</p>
<p>So the validation always trusts certificate X, and it checks if it can trust Y based upon the former. If so, it assigns X := Y and continues until it reaches the last certificate in the chain.</p>
<p>These four are the main checks that are made:</p>
<ol>
<li>The signature in certificate Y is validated with public key contained in certificate X.</li>
<li>The Issuer part in certificate Y matches exactly the Subject of certificate X.</li>
<li>Certificate Y&#8217;s validity period covers the time for which the chain is validated (the system clock time, or the timestamp&#8217;s time if such is applied).</li>
<li>Certificate Y is not revoked.</li>
</ol>
<p>Chapter 6 wouldn&#8217;t reach 20 pages if it was this simple, however much of the rambling in that chapter relates to certificate policies and other restrictions. The takeaway from this list of 4 criteria is where the focus is on walking from one certificate to another: The validation of the signature and matching the Subject / Issuer pairs.</p>
<p>I suppose that the Subject / Issuer check is there mostly to prevent certificates from being misleading to us humans: From a pure cryptographic point of view, no loopholes would have been created by skipping this test.</p>
<p>And this brings me back to what I started this post with: This whole thing with certificates has a bureaucratic side, and a cryptographic side. Both play a role.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2021/04/certificate-ca-tutorial-primer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache 2.4: RewriteRule with [NE] causing 500 Internal Server Error</title>
		<link>http://billauer.co.il/blog/2021/01/apache-rewriterule-percent-escape-internal-server-error/</link>
		<comments>http://billauer.co.il/blog/2021/01/apache-rewriterule-percent-escape-internal-server-error/#comments</comments>
		<pubDate>Sat, 23 Jan 2021 13:22:28 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6221</guid>
		<description><![CDATA[This is the weirdest thing. With an Apache 2.4.10 on Linux Debian 8 (yes, old), and a relatively simple mod_rewrite rule in .htaccess going RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteRule (.*) https://www.mysite.com/$1 [R=301,L,NE] This is really nothing special. Just pushing users to the www host name, if they were lazy typing it. This works almost perfectly, [...]]]></description>
			<content:encoded><![CDATA[<p>This is the weirdest thing. With an Apache 2.4.10 on Linux Debian 8 (yes, old), and a relatively simple mod_rewrite rule in .htaccess going</p>
<pre>RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.mysite.com/$1 [R=301,L,<span style="color: #ff0000;"><strong>NE</strong></span>]</pre>
<p>This is really nothing special. Just pushing users to the www host name, if they were lazy typing it.</p>
<p>This works almost perfectly, but then I have this thing about trying odd stuff. So I get an internal server error when I request the page https://mysite.com/%01, but not mysite.com/%1 and not mysite.com/%20. In other words, I get a server error when there&#8217;s a legal percent-escape of a character in the %01-%1f range. Not with %00, and not with %20 and up, and not when there&#8217;s just one digit. It&#8217;s really a matter of a proper percent escape.</p>
<p>This %-escape doesn&#8217;t have to be in the beginning of the string. https://mysite.com/mything%01.html is equally offensive. But it appears like a &#8220;?&#8221; neutralizes the problem &#8212; there is no server error if a &#8220;?&#8221; appeared before the offending %-escape. Recall that characters after a &#8220;?&#8221; are normally not escaped.</p>
<p>And of course, there is no problem accessing https://www.mysite.com/mything%01.html (getting a 404, but fine), as the rule doesn&#8217;t come to effect.</p>
<p>The internal server error leaves no traces in neither the error log nor the access log. So there&#8217;s no hint there. Neither in the journalctl log. No process dies either.</p>
<p>The problem is clearly the NE flag (marked red above), telling mod_rewrite not to escape the the string it rewrites. Why this is an issue is beyond me. I could try asking in forums and such, but I have hunch on the chances getting an answer.</p>
<p>Exactly the same behavior is observed when this rule is in an Apache configuration file (in &lt;Virtualhost&gt; context).</p>
<p>So I just dropped the NE flag. Actually, this is a note to self explaining why I did it.</p>
<p>One could argue that it&#8217;s pretty harmless to get an error on really weird URL requests, however often a serious vulnerability begins with something that just went a little wrong. So I prefer to stay away.</p>
<p>If anyone has insights on this matter, please comment below. Maybe it has been silently fixed in later versions of Apache?</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2021/01/apache-rewriterule-percent-escape-internal-server-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Systemd services as cronjobs: No process runs away</title>
		<link>http://billauer.co.il/blog/2021/01/systemd-cron-cgroups/</link>
		<comments>http://billauer.co.il/blog/2021/01/systemd-cron-cgroups/#comments</comments>
		<pubDate>Mon, 18 Jan 2021 06:10:06 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[Server admin]]></category>
		<category><![CDATA[systemd]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6214</guid>
		<description><![CDATA[But why? Cronjobs typically consists of a single utility which we&#8217;re pretty confident about. Even if it takes quite some time to complete (updatedb, for example), there&#8217;s always a simple story, a single task to complete with a known beginning and end. If the task involves a shell script that calls a few utilities, that [...]]]></description>
			<content:encoded><![CDATA[<h3>But why?</h3>
<p>Cronjobs typically consists of a single utility which we&#8217;re pretty confident about. Even if it takes quite some time to complete (updatedb, for example), there&#8217;s always a simple story, a single task to complete with a known beginning and end.</p>
<p>If the task involves a shell script that calls a few utilities, that feeling of control fades. It&#8217;s therefore reassuring to know that everything can be cleaned up neatly by simple stopping a service. Systemd is good at that, since all processes that are involved in the service are kept in a separate cgroup. So when the service is stopped, all processes that were possibly generated eventually get a SIGKILL, typically 90 seconds after the request to stop the service, unless they terminated voluntarily in response to the initial SIGTERM.</p>
<p>Advantage number two is that the systemd allows for a series of capabilities to limit what the cronjob is capable of doing, thanks to the cgroup arrangement. This doesn&#8217;t fall very short from the possibilities of container virtualization, with pretty simple assignments in the unit file. This includes making certain directories inaccessible or accessible for read-only, setting up temporary directories, disallow external network connection, limit the set of allowed syscalls, and of course limit the amount of resources that are consumed by the service. They&#8217;re called Control Groups for a reason.</p>
<p>There&#8217;s also the RuntimeMaxSec parameter in the service unit file, which is the maximal wall clock time the service is allowed to run. The service is terminated and put in failure state if this time   is exceeded. This is however supported from systemd version 229 and later, so check with  &#8220;systemctl &#8211;version&#8221;.</p>
<p>My original idea was to use systemd timers to kick off the job, and let RuntimeMaxSec make sure it would get cleaned up if it ran too long (i.e. got stuck somehow). But because the server in question ran a rather old version of systemd, I went for a cron entry for starting the service and another one for stopping it, with a certain time difference between them. In hindsight, cron turned to be neater for kicking off the jobs, because I had multiple variants of them in different times. So one single file enclosed all.</p>
<p>The main practical difference is that if a service reaches RuntimeMaxSec, it&#8217;s terminated with a failed status. The cron solution stops the service without this. I guess there&#8217;s a systemctl way to achieve the failed status, if that&#8217;s really important.</p>
<p>As a side note, I have a <a href="http://billauer.co.il/blog/2020/06/firejail-cgroups/" target="_blank">separate post</a> on Firejail, which is yet another possibility to use cgroups for controlling what processes do.</p>
<h3>Timer basics</h3>
<p>The idea is simple: A service can be started as a result of a timer event. That&#8217;s all that timer units do.</p>
<p>Timer units are configured like any systemd units (man systemd.unit)   but have a .timer suffix and a dedicated [Timer] section. By  convention,  the timer unit named foo.timer activates the service  foo.service,  unless specified differently with the Unit= assignment  (useful for  generating confusion).</p>
<p>Units that are already running when the timer event occurs are not restarted, but are left to keep running. Exactly like systemctl start would do.</p>
<p>For an cronjob-style timer, use OnCalendar= to specify the times. See  man systemd.time for the format. Note that AccuracySec= should be set  too to control how much systemd can play with the exact time of  execution, or systemd&#8217;s behavior might be confusing.</p>
<p>To see all active timers, go</p>
<pre>$ systemctl list-timers</pre>
<h3>The unit file</h3>
<p>As usual, the unit file (e.g. /etc/systemd/system/cronjob-test@.service) is short and concise:</p>
<pre>[Unit]
Description=Cronjob test service

[Service]
ExecStart=/home/eli/shellout/utils/shellout.pl "%I"
Type=simple
User=eli
WorkingDirectory=/home/eli/shellout/utils
KillMode=mixed
<span style="text-decoration: line-through;">NoNewPrivileges=true</span></pre>
<p>This is a simple service, meaning that systemd expects the process launched by ExecStart to run in the foreground.</p>
<p>Note however that the service unit&#8217;s file name has a &#8220;@&#8221; character and that %I is used to choose what to run, based upon the unescaped instance name (see main systemd.unit). This turns the unit file into a template, and allows choosing an arbitrary command (the shellout.pl script is explained below) with something like (really, this works)</p>
<pre># systemctl start cronjob-test@'echo "Hello, world"'</pre>
<p>This might seems dangerous, but recall that root privileges are required  to start the service, and you get a plain-user process (possibly with no ability  to escalate privileges) in return. Not the big jackpot.</p>
<p>For stopping the service, exactly the same service specifier string is required. But it&#8217;s also possible to stop all instances of a service with</p>
<pre># systemctl stop 'cronjob-test@*'</pre>
<p>How neat is that?</p>
<p>A few comments on this:</p>
<ul>
<li>The service should not be systemd-wise enabled (i.e. no &#8220;systemctl enable&#8221;) &#8212; that&#8217;s what you do to get it started on boot or following some kind of event. This is not the case, as the whole point is to start the service directly by a timer or crond.</li>
<li>Accordingly, the service unit file does <strong>not</strong> have an [Install] section.</li>
<li>A side effect of this is that the service may not appear in the list made by &#8220;systemctl&#8221; (without any arguments) unless it has processes running on its behalf currently running (or possibly if it&#8217;s in the failed state). Simple logic: It&#8217;s not loaded unless it has a cgroup allocated, and the cgroup is removed along with the last process. But it may appear anyhow under some conditions.</li>
<li>ExecStart must have a full path (i.e. not relative) even if the WorkingDirectory is set. In particular, it can&#8217;t be ./something.</li>
<li>A &#8220;systemctl start&#8221; on a service that is marked as failed will be started anyhow (i.e. the fact that it&#8217;s marked failed doesn&#8217;t prevent that). Quite obvious, but I tested it to be sure.</li>
<li>Also, a &#8220;systemctl start&#8221; causes the execution of ExecStart if and only if there&#8217;s no cgroup for it, which is equivalent to not having a process running on its behalf</li>
<li>KillMode is set to &#8220;mixed&#8221; which sends a SIGTERM only to the process that is launched directly when the service is stopped. The SIGKILL 90 seconds later, if any, is sent to all processes however. The default is to give all processes in the cgroup the SIGTERM when stopping.</li>
<li>NoNewPrivileges is a little paranoid thing: When no process has any reason to change its privileges or user IDs,  block this possibility. This mitigates damage, should the job be successfully attacked in some way. But I ended up not using it, as running sendmail fails (it has some setuid thing to allow access to the mail spooler).</li>
</ul>
<h3>Stopping</h3>
<p>There is no log entry for a service of simple type that terminates with a success status. Even though it&#8217;s stopped in the sense that it has no allocated cgroup and &#8220;systemctl start&#8221; behaves as if it was stopped, a successful termination is silent. Not sure if I like this, but that&#8217;s the way it is.</p>
<p>When the process doesn&#8217;t respond to SIGTERM:</p>
<pre>Jan 16 19:13:03 systemd[1]: <strong>Stopping</strong> Cronjob test service...
Jan 16 19:14:33 systemd[1]: cronjob-test.service stop-sigterm timed out. Killing.
Jan 16 19:14:33 systemd[1]: cronjob-test.service: main process exited, code=killed, status=9/KILL
Jan 16 19:14:33 systemd[1]: <strong>Stopped</strong> Cronjob test service.
Jan 16 19:14:33 systemd[1]: Unit cronjob-test.service entered failed state.</pre>
<p>So there&#8217;s always &#8220;Stopping&#8221; first and then &#8220;Stopped&#8221;. And if there are processes in the control group 90 seconds after &#8220;Stopping&#8221;, SIGKILL is sent, and the service gets a &#8220;failed&#8221; status. Not being able to quit properly is a failure.</p>
<p>A &#8220;systemctl stop&#8221; on a service that is already stopped is legit: The systemctl utility returns silently with a success status, and a &#8220;Stopped&#8221; message appears in the log without anything actually taking place. Neither does the service&#8217;s status change, so if it was considered failed before, so it remains. And if the target to stop was a group if instances (e.g. systemctl stop &#8216;cronjob-test@*&#8217;) and there were no instances to stop, there&#8217;s even not a log message on that.</p>
<p>Same logic with &#8220;Starting&#8221; and &#8220;Started&#8221;: A superfluous &#8220;systemctl start&#8221; does nothing except for a &#8220;Started&#8221; log message, and the utility is silent, returning success.</p>
<h3>Capturing the output</h3>
<p>By default, the output (stdout and  stderr) of the processes is logged in the journal. This is usually  pretty convenient, however I wanted the good old cronjob behavior: An  email is sent unless the job is completely silent and exits with a success  status (actually, crond doesn&#8217;t care, but I wanted this too).</p>
<p>This  concept doesn&#8217;t fit systemd&#8217;s spirit: You don&#8217;t start sending mails  each time a service has something to say. One could use OnFailure for  activating another service that calls home when the service gets into a  failure status (which includes a non-success termination of the main  process), but that mail won&#8217;t tell me the output. To achieve this, I wrote a  Perl script. So there&#8217;s one extra process, but who cares, systemd  kills&#8217;em all in the end anyhow.</p>
<p>Here it comes (I called it shellout.pl):</p>
<pre>#!/usr/bin/perl

use strict;
use warnings;

# Parameters for sending mail to report errors
my $sender = 'eli';
my $recipient = 'eli';
my $sendmail = "/usr/sbin/sendmail -i -f$sender";

my $cmd = shift;
my $start = time();

my $output = '';

my $catcher = sub { finish("Received signal."); };

$SIG{HUP} = $catcher;
$SIG{TERM} = $catcher;
$SIG{INT} = $catcher;
$SIG{QUIT} = $catcher;

my $pid = open (my $fh, '-|');

finish("Failed to fork: $!")
  unless (defined $pid);

if (!$pid) { # Child process
  # Redirect stderr to stdout for child processes as well
  open (STDERR, "&gt;&amp;STDOUT");

  exec($cmd) or die("Failed to exec $cmd: $!\n");
}

# Parent
while (defined (my $l = &lt;$fh&gt;)) {
  $output .= $l;
}

close $fh
 or finish("Error: $! $?");

finish("Execution successful, but output was generated.")
 if (length $output);

exit 0; # Happy end
sub finish {
  my ($msg) = @_;

  my $elapsed = time() - $start;

  $msg .= "\n\nOutput generated:\n\n$output\n"
    if (length $output);

  open (my $fh, '|-', "$sendmail $recipient") or
    finish("Failed to run sendmail: $!");

  print $fh &lt;&lt;"END";
From: Shellout script &lt;$sender&gt;
Subject: systemd cron job issue
To: $recipient

The script with command \"$cmd\" ran $elapsed seconds.

$msg
END

  close $fh
    or die("Failed to send email: $! $?\n");

  $SIG{TERM} = sub { }; # Not sure this matters
  kill -15, $$; # Kill entire process group

  exit(1);
}</pre>
<p>First, let&#8217;s pay attention to</p>
<pre>open (STDERR, "&gt;&amp;STDOUT");</pre>
<p>which makes sure standard error is redirected to standard output. This is inherited by child processes, which is exactly the point.</p>
<p>The script catches the signals (SIGTERM in particular, which is systemd&#8217;s first hint that it&#8217;s time to pack and leave) and sends a SIGTERM to all other processes in turn. This is combined with KillMode being set to &#8220;mixed&#8221; in the service unit file, so that only shellout.pl gets the signal, and not the other processes.</p>
<p>The rationale is that if all processes get the signal at once, it may (theoretically?) turn out that the child process terminates before the script reacted to the signal it got itself, so it will fail to report that the reason for the termination was a signal, as opposed to the termination of the child. This could miss a situation where the child process got stuck and said nothing when being killed.</p>
<p>Note that the script kills all processes in the process group just before quitting due to a signal it got, or when the invoked process terminates and there was output. Before doing so, it sets the signal handler to a NOP, to avoid an endless loop, since the script&#8217;s process will get it as well (?). This NOP thing appears to be unnecessary, but better safe than sorry.</p>
<p>Also note that the while loop quits when there&#8217;s nothing more in &lt;$fh&gt;. This means that if the child process forks and then terminates, the while loop will continue, because unless the forked process closed its output file handles, it will keep the reference count of the script&#8217;s stdin above zero. The first child process will remain as a zombie until the forked process is done. Only then will it be reaped by virtue of the close $fh. This machinery is not intended for fork() sorcery.</p>
<p>I took a different approach in <a href="http://billauer.co.il/blog/2020/10/perl-fork-ipc-kill-children/" target="_blank">another post of mine</a>, where the idea was to fork explicitly and modify the child&#8217;s attributes. <a href="http://billauer.co.il/blog/2013/03/fork-wait-and-the-return-values-in-perl-in-different-scenarios/" target="_blank">Another post</a> discusses timing out a child process in general.</p>
<h3>Summary</h3>
<p>Yes, cronjobs are much simpler. But in the long run, it&#8217;s a good idea to acquire the ability to run cronjobs as services for the sake of keeping the system clean from runaway processes.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2021/01/systemd-cron-cgroups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing to a disk even when df says zero available space</title>
		<link>http://billauer.co.il/blog/2020/08/backup-more-than-full/</link>
		<comments>http://billauer.co.il/blog/2020/08/backup-more-than-full/#comments</comments>
		<pubDate>Fri, 14 Aug 2020 07:23:48 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6102</guid>
		<description><![CDATA[Just a quick note to remind myself: There&#8217;s a gap between the size of a disk, the used space and the available space. It&#8217;s quite well-known that a certain percentage of the disk (that&#8217;s 200 GB on a 3.6 TB backup disk) is saved for root-only writes. So the reminder is: No problem filling the [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick note to remind myself: There&#8217;s a gap between the size of a disk, the used space and the available space. It&#8217;s quite well-known that a certain percentage of the disk (that&#8217;s 200 GB on a 3.6 TB backup disk) is saved for root-only writes.</p>
<p>So the reminder is: No problem filling the disk beyond the Available = zero blocks point if you&#8217;re root. And it doesn&#8217;t matter if the files written don&#8217;t belong to root. The show goes on.</p>
<p>Also, the numbers shown by df are updated only when the file written to is closed. So if a very long file is being copied, it might freeze for a while, and then boom.</p>
<p>This is important in particular when using the disk just for backing up data, because the process doing the backup is root, but the files aren&#8217;t.</p>
<p>But whatever you do, <strong>don&#8217;t press CTRL-C</strong> while the extracting goes on. If tar quits in the middle, there will be file ownerships and permissions unset, and symlinks set to zero-length files too. It wrecks the entire backup, even in places far away from where tar was working when it was stopped.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2020/08/backup-more-than-full/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Root over NFS remains read only with Linux v5.7</title>
		<link>http://billauer.co.il/blog/2020/07/nfsroot-read-only-remount/</link>
		<comments>http://billauer.co.il/blog/2020/07/nfsroot-read-only-remount/#comments</comments>
		<pubDate>Sun, 26 Jul 2020 13:18:22 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Linux kernel]]></category>
		<category><![CDATA[Server admin]]></category>
		<category><![CDATA[systemd]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6078</guid>
		<description><![CDATA[Upgrading the kernel should be quick and painless&#8230; After upgrading the kernel from v5.3 to 5.7, a lot of systemd services failed (Debian 8), in particular systemd-remount-fs: ● systemd-remount-fs.service - Remount Root and Kernel File Systems Loaded: loaded (/lib/systemd/system/systemd-remount-fs.service; static) Active: failed (Result: exit-code) since Sun 2020-07-26 15:28:15 IDT; 17min ago Docs: man:systemd-remount-fs.service(8) http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems Process: [...]]]></description>
			<content:encoded><![CDATA[<h3>Upgrading the kernel should be quick and painless&#8230;</h3>
<p>After upgrading the kernel from v5.3 to 5.7, a lot of systemd services failed (Debian 8), in particular systemd-remount-fs:</p>
<pre>● systemd-remount-fs.service - Remount Root and Kernel File Systems
   Loaded: loaded (/lib/systemd/system/systemd-remount-fs.service; static)
   Active: failed (Result: exit-code) since Sun 2020-07-26 15:28:15 IDT; 17min ago
     Docs: man:systemd-remount-fs.service(8)

http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems

  Process: 223 ExecStart=/lib/systemd/systemd-remount-fs (code=exited, status=1/FAILURE)
 Main PID: 223 (code=exited, status=1/FAILURE)

Jul 26 15:28:15 systemd[1]: systemd-remount-fs.service: main process exited, code=exited, status=1/FAILURE
Jul 26 15:28:15 systemd[1]: Failed to start Remount Root and Kernel File Systems.
Jul 26 15:28:15 systemd[1]: Unit systemd-remount-fs.service entered failed state.</pre>
<p>and indeed, the root NFS remained read-only (checked with &#8220;mount&#8221; command), which explains why so many other services failed.</p>
<p>After an strace session, I managed to nail down the problem: The system call to mount(), which was supposed to do the remount, simply failed:</p>
<pre>mount("10.1.1.1:/path/to/debian-82", "/", 0x61a250, MS_REMOUNT, "addr=10.1.1.1") = -1 EINVAL (Invalid argument)</pre>
<p>On the other hand, any attempt to remount another read-only NFS mount, which had been mounted the regular way (i.e. after boot) went through clean, of course:</p>
<pre>mount("10.1.1.1:/path/to/debian-82", "/mnt/tmp", 0x61a230, MS_REMOUNT, "addr=10.1.1.1") = 0</pre>
<p>The only apparent difference between the two cases is the third argument, which is ignored for MS_REMOUNT according to the manpage.</p>
<p>The manpage also says something about the EINVAL return value:</p>
<blockquote><p>EINVAL   A remount operation (MS_REMOUNT) was attempted, but  source was not already mounted on target.</p></blockquote>
<p>A hint to the problem could be that the type of the mount, as listed in /proc/mounts,  is &#8220;nfs&#8221; for the root mounted filesystem, but &#8220;nfs4&#8243; for the one in /mnt/tmp. The reason for this difference isn&#8217;t completely clear.</p>
<h3>The solution</h3>
<p>So it&#8217;s all about that little hint: If the nfsroot is selected to boot as version 4, then there&#8217;s no problem remounting it. Why it made a difference from one kernel version to another is beyond me. So the fix is to add nfsvers=4 to the nfsroot assignment. Something like</p>
<pre>root=/dev/nfs nfsroot=10.1.1.1:/path/to/debian-82,<span style="color: #ff0000;"><strong>nfsvers=4</strong></span></pre>
<p>For the record, I re-ran the remount command with strace again, and exactly the same system call was made, including that most-likely-ignored 0x61a250 argument, and it simply returned success (zero) instead of EINVAL.</p>
<p>As a side note, the rootfstype=nfs in the kernel command line is  completely ignored. Write any junk instead of &#8220;nfs&#8221; and it makes no  difference.</p>
<p>Another yak shaved successfully.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2020/07/nfsroot-read-only-remount/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Turning off DSN on sendmail to prevent backscatter</title>
		<link>http://billauer.co.il/blog/2020/07/dsn-backscatter-spam-sendmail/</link>
		<comments>http://billauer.co.il/blog/2020/07/dsn-backscatter-spam-sendmail/#comments</comments>
		<pubDate>Wed, 15 Jul 2020 12:06:15 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[email]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6071</guid>
		<description><![CDATA[I sent that? One morning, I got a bounce message from my own mail sendmail server, saying that it failed to deliver a message I never sent. That&#8217;s red alert. It means that someone managed to provoke my mail server to send an outbound message. It&#8217;s red alert, because my mail server effectively relays spam [...]]]></description>
			<content:encoded><![CDATA[<h3>I sent that?</h3>
<p>One morning, I got a bounce message from my own mail sendmail server, saying that it failed to deliver a message I never sent. That&#8217;s red alert. It means that someone managed to provoke my mail server to send an outbound message. It&#8217;s red alert, because my mail server effectively relays spam to any destination that the spammer chooses. This could ruin the server&#8217;s reputation horribly.</p>
<p>It turned out that an arriving mail required a return receipt, which was destined to just some mail address. There&#8217;s an SMTP feature called Delivery Status Notification (DSN), which allows the client connecting to the mail server to ask for a mail &#8220;in return&#8221;, informing the sender of the mail if it was properly delivered. The problem is that the MAIL FROM / From addresses could be spoofed, pointing at a destination to spam. Congratulations, your mail server was just tricked into sending spam. This kind of trickery is called backscatter.</p>
<p>Checking my own mail logs, the DSN is a virtually unused feature. So it&#8217;s probably just something spammers can take advantage of.</p>
<p>The relevant RFC for DSN is <a href="https://tools.ietf.org/html/rfc1891" target="_blank">RFC1891</a>. Further explanations on DSN can be found <a href="https://www.sendmail.org/~ca/email/dsn.html" target="_blank">in one of sendmail&#8217;s tutorial pages</a>.</p>
<h3>How to turn DSN off</h3>
<p>First, I recommend checking if it&#8217;s not disabled already, as explained below. In particular, if the paranoid-level &#8220;goaway&#8221; privacy option is used, DSN is turned off anyhow.</p>
<p>It&#8217;s actually easy. Add the noreceipts option to PrivacyOptions. More  precisely, edit /etc/mail/sendmail.mc and add noreceipts to the list of  already existing options. In my case, it ended up as</p>
<pre>define(`confPRIVACY_FLAGS',dnl
`needmailhelo,needexpnhelo,needvrfyhelo,restrictqrun,restrictexpand,nobodyreturn,noetrn,noexpn,novrfy,noactualrecipient,<span style="color: #ff0000;"><strong>noreceipts</strong></span>')dnl</pre>
<p>and then run &#8220;make&#8221; in /etc/mail, and restart sendmail.</p>
<p>Turning off DSN is often recommended against in different sendmail guides, because it&#8217;s considered a &#8220;valuable feature&#8221; or so. As mentioned above, I haven&#8217;t seen it used by anyone else than spammers.</p>
<h3>Will my mail server do DSN?</h3>
<p>Easy to check, because the server announces its willingness to fulfill DSN requests at the beginning of the SMTP session, with the line marked in red in the sample session below:</p>
<pre>&lt;&lt;&lt; 220 mx.mymailserver.com ESMTP MTA; Wed, 15 Jul 2020 10:22:32 GMT
&gt;&gt;&gt; EHLO localhost.localdomain
&lt;&lt;&lt; 250-mx.mymailserver.com Hello 46-117-33-227.bb.netvision.net.il [46.117.33.227], pleased to meet you
&lt;&lt;&lt; 250-ENHANCEDSTATUSCODES
&lt;&lt;&lt; 250-PIPELINING
&lt;&lt;&lt; 250-8BITMIME
&lt;&lt;&lt; 250-SIZE
&lt;&lt;&lt; <span style="color: #ff0000;"><strong>250-DSN</strong></span>
&lt;&lt;&lt; 250-DELIVERBY
&lt;&lt;&lt; 250 HELP
&gt;&gt;&gt; MAIL FROM:&lt;spamvictim@billauer.co.il&gt;
&lt;&lt;&lt; 250 2.1.0 &lt;spamvictim@billauer.co.il&gt;... Sender ok
&gt;&gt;&gt; RCPT TO:&lt;legal_address@billauer.co.il&gt; <strong>NOTIFY=SUCCESS</strong>
&lt;&lt;&lt; 250 2.1.5 &lt;legal_address@billauer.co.il&gt;... Recipient ok
&gt;&gt;&gt; DATA
&lt;&lt;&lt; 354 Enter mail, end with "." on a line by itself
&gt;&gt;&gt; MIME-Version: 1.0
&gt;&gt;&gt; From: spamvictim@billauer.co.il
&gt;&gt;&gt; To: legal_address@billauer.co.il
&gt;&gt;&gt; Subject: Testing email.
&gt;&gt;&gt;
&gt;&gt;&gt;
&gt;&gt;&gt; Just a test, please ignore
&gt;&gt;&gt; .
&lt;&lt;&lt; 250 2.0.0 06FAMWa1014200 Message accepted for delivery
&gt;&gt;&gt; QUIT
&lt;&lt;&lt; 221 2.0.0 mx.mymailserver.com closing connection</pre>
<p>To test a mail server for its behavior with DSN, the script that <a href="http://billauer.co.il/blog/2013/01/perl-sendmail-exim-postfix-test/" target="_blank">I&#8217;ve already published</a> can be used. To make it request a return receipt, the two lines that set the SMTP recipient should be changed to</p>
<pre>  die("Failed to set receipient\n")
    if (! ($smtp-&gt;recipient( ($to_addr ), { Notify =&gt; ['SUCCESS'] } ) ) );</pre>
<p>This change causes the NOTIFY=SUCCESS part in the RCPT TO line, which effectively requests a receipt from the server when the mail is properly delivered.</p>
<p>Note that if DSN isn&#8217;t supported by the mail server (possibly because of the privacy option fix shown above), the SMPT session looks exactly the same, except that the SMTP line marked in red will be absent. Then the mail server just ignores the NOTIFY=SUCCESS part silently, and responds exactly as before.</p>
<p>However when running the Perl script, the Net::SMTP will be kind enough to issue a warning to its stderr:</p>
<pre>Net::SMTP::recipient: DSN option not supported by host at ./testmail.pl line 36.</pre>
<p>The mail addresses I used in the sample session above are bogus, of courses, but note that the spam victim is the sender of the email, because that&#8217;s where the return receipt goes. On top of that, the RCPT TO address will also get a spam message, but that&#8217;s the smaller problem, as it&#8217;s yet another spam message arriving &#8212; not one that is sent away from our server.</p>
<p>I should also mention that Notify can be a comma-separated list of events, e.g.</p>
<pre>RCPT TO:&lt;bad_address@billauer.co.il&gt; NOTIFY=SUCCESS,FAILURE,DELAY</pre>
<p>however FAILURE doesn&#8217;t include the user not being known to the  server, in which case the message is dropped anyhow without any DSN  message generated. So as a spam trick, one can&#8217;t send mails to random addresses, and issue spam bounce messages because they failed. That would have been too easy.</p>
<h3>In the mail logs</h3>
<p>The sample session shown above causes the following lines in mail.log. Note the line marked in red, which indicates that the return receipt mechanism was fired off.</p>
<pre>Jul 15 10:15:31 sm-mta[12697]: 06FAFTbL012697: from=&lt;spamvictim@billauer.co.il&gt;, size=121, class=0, nrcpts=1, msgid=&lt;202007151015.06FAFTbL012697@mx.mymailserver.com&gt;, proto=ESMTP, daemon=IPv4-port-587, relay=46-117-33-227.bb.netvision.net.il
[46.117.33.227]
Jul 15 10:15:31 sm-mta[12698]: 06FAFTbL012697: to=&lt;legal_address@billauer.co.il&gt;, ctladdr=&lt;spamvictim@billauer.co.il&gt; (1010/500), delay=00:00:01, xdelay=00:00:00, mailer=local, pri=30456, dsn=2.0.0, stat=Sent
Jul 15 10:15:31 sm-mta[12698]: 06FAFTbL012697: 06FAFVbL012698: <span style="color: #ff0000;"><strong>DSN: Return receipt</strong></span>
Jul 15 10:15:31 sm-mta[12698]: 06FAFVbL012698: to=&lt;spamvictim@billauer.co.il&gt;, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=30000, dsn=2.0.0, stat=Sent</pre>
<h3>The receipt</h3>
<p>Since I&#8217;m at it, this is what a receipt message for the sample session above looks like:</p>
<pre>Received: from localhost (localhost)	by mx.mymailserver.com
 (8.14.4/8.14.4/Debian-8+deb8u2) id 06FAFVbL012698;	Wed, 15 Jul 2020
 10:15:31 GMT
Date: Wed, 15 Jul 2020 10:15:31 GMT
From: Mail Delivery Subsystem &lt;MAILER-DAEMON@billauer.co.il&gt;
Message-ID: &lt;202007151015.06FAFVbL012698@mx.mymailserver.com&gt;
To: &lt;spamvictim@billauer.co.il&gt;
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
 boundary="06FAFVbL012698.1594808131/mx.mymailserver.com"
Subject: Return receipt
Auto-Submitted: auto-generated (return-receipt)
X-Mail-Filter: main

This is a MIME-encapsulated message

--06FAFVbL012698.1594808131/mx.mymailserver.com

The original message was received at Wed, 15 Jul 2020 10:15:30 GMT
from 46-117-33-227.bb.netvision.net.il [46.117.33.227]

   ----- The following addresses had successful delivery notifications -----
&lt;legal_address@billauer.co.il&gt;  (successfully delivered to mailbox)

   ----- Transcript of session follows -----
&lt;legal_address@billauer.co.il&gt;... Successfully delivered

--06FAFVbL012698.1594808131/mx.mymailserver.com
Content-Type: message/delivery-status

Reporting-MTA: dns; mx.mymailserver.com
Received-From-MTA: DNS; 46-117-33-227.bb.netvision.net.il
Arrival-Date: Wed, 15 Jul 2020 10:15:30 GMT

Final-Recipient: RFC822; legal_address@billauer.co.il
Action: delivered (to mailbox)
Status: 2.1.5
Last-Attempt-Date: Wed, 15 Jul 2020 10:15:31 GMT

--06FAFVbL012698.1594808131/mx.mymailserver.com
Content-Type: text/rfc822-headers

Return-Path: &lt;spamvictim@billauer.co.il&gt;
Received: from localhost.localdomain (46-117-33-227.bb.netvision.net.il [46.117.33.227])
	by mx.mymailserver.com (8.14.4/8.14.4/Debian-8+deb8u2) with ESMTP id 06FAFTbL012697
	for &lt;legal_address@billauer.co.il&gt;; Wed, 15 Jul 2020 10:15:30 GMT
Date: Wed, 15 Jul 2020 10:15:29 GMT
Message-Id: &lt;202007151015.06FAFTbL012697@mx.mymailserver.com&gt;
MIME-Version: 1.0
From: spamvictim@billauer.co.il
To: legal_address@billauer.co.il
Subject: Testing email.

--06FAFVbL012698.1594808131/mx.mymailserver.com--</pre>
<p>But note that if DSN is used by a spammer to trick our mail server, we will get the failure notice that results from sending this message to the other server. If we&#8217;re lucky enough to get anything at all: If the message is accepted, we&#8217;ll never know our server has been sending spam.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2020/07/dsn-backscatter-spam-sendmail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When umount says target is busy, but no process can be blamed</title>
		<link>http://billauer.co.il/blog/2020/06/umount-restart-nfs/</link>
		<comments>http://billauer.co.il/blog/2020/06/umount-restart-nfs/#comments</comments>
		<pubDate>Sun, 28 Jun 2020 10:15:54 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>
		<category><![CDATA[systemd]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6067</guid>
		<description><![CDATA[A short one: What to do if unmount is impossible with a # umount /path/to/mount umount: /path/to/mount: target is busy but grepping the output of lsof for the said path yields nothing. In other words, the mount is busy, but no process can be blamed for accessing it (even as a home directory). If this [...]]]></description>
			<content:encoded><![CDATA[<p>A short one: What to do if unmount is impossible with a</p>
<pre># umount /path/to/mount
umount: /path/to/mount: target is busy</pre>
<p>but grepping the output of lsof for the said path yields nothing. In other words, the mount is busy, but no process can be blamed for accessing it (even as a home directory).</p>
<p>If this happens, odds are that it&#8217;s an NFS mount, held by some remote machine. The access might have been over long ago, but the mount is still considered busy. So the solution for this case is simple: Restart the NFS daemon. On Linux Mint 19 (and probably a lot of others) it&#8217;s simply</p>
<pre># systemctl restart nfs-server</pre>
<p>and after this, umount is sucessful (hopefully&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2020/06/umount-restart-nfs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Firejail: Putting a program in its own little container</title>
		<link>http://billauer.co.il/blog/2020/06/firejail-cgroups/</link>
		<comments>http://billauer.co.il/blog/2020/06/firejail-cgroups/#comments</comments>
		<pubDate>Thu, 11 Jun 2020 03:39:11 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server admin]]></category>
		<category><![CDATA[Virtualization]]></category>

		<guid isPermaLink="false">http://billauer.co.il/blog/?p=6049</guid>
		<description><![CDATA[Introduction Firejail is a lightweight security utility which ties the hands of running processes, somewhat like Apparmor and SELinux. However it takes the mission towards Linux kernel&#8217;s cgroups and namespaces. It&#8217;s in fact a bit of a container-style virtualization utility, which creates sandboxes for running specific programs: Instead of a container for an entire operating [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Firejail is a lightweight security utility which ties the hands of running processes, somewhat like Apparmor and SELinux. However it takes the mission towards Linux kernel&#8217;s cgroups and namespaces.  It&#8217;s in fact a bit of a container-style virtualization utility, which creates sandboxes for running specific programs: Instead of a container for an entire operating system, it makes one for each application (i.e. the main process and its children). Rather than disallowing access from files and directories by virtue of permissions, simply make sure they aren&#8217;t visible to the processes. Same goes for networking.</p>
<p>By virtue of Cgroups, several security restrictions are also put in place regardless if so desired. Certain syscalls can be prevented etc. But in the end of the day, think container virtualization. A sandbox is created, and everything happens inside it. It&#8217;s also easy to add processes to an existing sandbox (in particular, start a new shell). Not to mention the joy of shutting down a sandbox, that is, killing all processes inside it.</p>
<p>While the main use of Firejail  to protect the file system from access and tampering by malicious or infected software, it also allows more or less everything that a container-style virtual machine does: Control of network traffic (volume, dedicated firewall, which physical interfaces are exposed) as well as activity (how many subprocesses, CPU and memory utilization etc.). And like a virtual machine, it also allows statistics on resource usage.</p>
<p>Plus spoofing the host name, restricting access to sound devices, X11 capabilities and a whole range of stuff.</p>
<p>And here&#8217;s the nice thing: It <strong>doesn&#8217;t require root</strong> privileges to run. Sort of. The firejail executable is run with setuid.</p>
<p>It&#8217;s however important to note that firejail <strong>doesn&#8217;t create a stand-alone container</strong>. Rather, it mixes and matches files from the real file system and overrides selected parts of the directory tree with temporary mounts. Or overlays. Or whiteouts.</p>
<p>In fact, compared with the accurate rules of a firewall, its behavior is quite loose and inaccurate. For a newbie, it&#8217;s a bit difficult to predict exactly what kind of sandbox it will set up given this or other setting. It throws in all kind of files of its own into the temporary directories it creates, which is very helpful to get things up and running quickly, but that doesn&#8217;t give a feeling of control.</p>
<p>Generally speaking, everything that isn&#8217;t explicitly handled by blacklisting or whitelisting (see below) is accessible in the sandbox just like outside it. In particular, it&#8217;s the user&#8217;s responsibility to hide away all those system-specific mounted filesystems (do you call them /mnt/storage?). If desired, of course.</p>
<p><strong>Major disclaimer:</strong> <strong>This post is not authoritative</strong> in any way, and contains my jots as I get to know the beast. In particular, I may mislead you to think something is protected even though it&#8217;s not. You&#8217;re responsible to your own decisions.</p>
<p>The examples below are with firejail version 0.9.52 on a Linux Mint 19.</p>
<h3>Install</h3>
<pre># apt install firejail
# apt install firetools</pre>
<p>By all means, go</p>
<pre>$ man firejail</pre>
<p>after installation. It&#8217;s also worth to look at /etc/firejail/ to get an idea on what protection measures are typically used.</p>
<h3>Key commands</h3>
<p>Launch FireTools, a GUI front end:</p>
<pre>$ firetools &amp;</pre>
<p>And the &#8220;Tools&#8221; part has a nice listing of running sandboxes (right-click the ugly thing that comes up).</p>
<p>Now some command line examples. I name the sandboxes in these examples, but I&#8217;m not sure it&#8217;s worth bothering.</p>
<p>List existing sandboxes (or use FireTools, right-click the panel and choose Tools):</p>
<pre>$ firejail --list</pre>
<p>Assign a name to a sandbox when creating it</p>
<pre>$ firejail --name=mysandbox firefox</pre>
<p>Shut down a sandbox (kill all its processes, and clean up):</p>
<pre>$ firejail --shutdown=mysandbox</pre>
<p>If a name wasn&#8217;t assigned, the PID given in the list can be used instead.</p>
<p>Disallow the root user in the sandbox</p>
<pre>$ firejail --noroot</pre>
<p>Create overlay filesystem (mounts read/write, but changes are kept elsewhere)</p>
<pre>$ firejail --overlay firefox</pre>
<p>There&#8217;s also &#8211;overlay-tmpfs for overlaying tmpfs only, as well as &#8211;overlay-clean to clean the overlays, which are stored in $HOME/.firejail.</p>
<p>To create a completely new home directory (and /root) as temporary filesystems (private browsing style), so they are volatile:</p>
<pre>$ firejail --private firefox</pre>
<p>Better still,</p>
<pre>$ firejail --private=/path/to/extra-homedir firefox</pre>
<p>This uses the directory in the given path as a <strong>persistent</strong> home directory (some basic files are added automatically). This path can be anywhere in the filesystem, even in parts that are otherwise hidden (i.e. blacklisted) to the sandbox. So this is probably the most appealing choice in most scenarios.</p>
<p>Don&#8217;t get too excited, though: Other mounted filesystems remain unprotected (at different levels). This just protects the home directory.</p>
<p>By default, a whole bunch of security rules are loaded when firejail is invoked. To start the container without this:</p>
<pre>$ firejail --noprofile</pre>
<p>A profile can be selected with the  &#8211;profile=filename flag.</p>
<h3>Writing a profile</h3>
<p>If you really want to have a sandbox that protects your computer with relation to a specific piece of software, you&#8217;ll probably have to write your own profile. It&#8217;s no big deal, except that it&#8217;s a bit of trial and error.</p>
<p>First read the manpage:</p>
<pre>$ man firejail-profile</pre>
<p>It&#8217;s easiest to start from a template: Launch FireTools from a shell, right-click the ugly thing that comes up, and pick &#8220;Configuration  Wizard&#8221;, and create a custom security profile for one of the listed application &#8212; the one that resembles most the one for which the profile is set up.</p>
<p>Then launch the application from FireTools. The takeaway is that it writes out the configuration file to the console. Start with that.</p>
<h3>Whilelisting and blacklisting</h3>
<p>First and foremost: Always run a</p>
<pre>$ df -h</pre>
<p>inside the sandbox to get an idea of what is mounted. Blacklist anything that isn&#8217;t necessary. Doing so to entire mounts removes the related mount from the df -h list, which makes it easier to spot things that shouldn&#8217;t be there.</p>
<p>It&#8217;s also a good idea to start a sample bash session with the sandbox, and get into the File Manager in the Firetool&#8217;s &#8220;Tools&#8221; section for each sandbox.</p>
<p>But then, what is whitelisting and blacklisting, exactly? These two terms are used all over the docs, somehow assuming we know what they mean. So I&#8217;ll try to nail it down.</p>
<p>Whitelisting isn&#8217;t anywhere near what one would think it is: By whitelisting certain files and/or directories, the original files/directories appear in the sandbox <strong>but all other files in their vicinity are invisible</strong>. Also, changes in the same vicinity are temporary to the sandbox session. The idea seems to be that if files and/or directories are whitelisted, everything else close to it should be out of sight.</p>
<p>Or as put in the man page:</p>
<blockquote><p>A temporary file system is mounted on the top directory, and the whitelisted files are mount-binded inside.  Modifications to whitelisted  files are persistent, everything else is discarded when the sandbox is closed. The top directory could be user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp.</p></blockquote>
<p>So for example, if any file or directory in the home directory is whitelisted, the entire home directory becomes overridden by an almost empty home directory plus the specifically whitelisted items. For example, from my own home directory (which is populated with a lot of files):</p>
<pre>$ firejail --noprofile --whitelist=/home/eli/this-directory
Parent pid 31560, child pid 31561
Child process initialized in 37.31 ms

$ find .
.
./.config
./.config/pulse
./.config/pulse/client.conf
./this-directory
./this-directory/this-file.txt
./.Xauthority
./.bashrc</pre>
<p>So there&#8217;s just a few temporary files that firejail was kind enough to add for convenience. Changes made in this-directory/ are persistent since it&#8217;s bind-mounted into the temporary directory, but <strong>everything else is temporary.</strong></p>
<p>Quite unfortunately, it&#8217;s not possible to whitelist a directory outside the specific list of hierarchies (unless bind mounting is used, but that requires root). So if the important stuff is one some /hugedisk, only a bind mount will help (or is this the punishment for not putting it has /mnt/hugedisk?).</p>
<p>But note that the &#8211;private= flag allows setting the home directory to anywhere on the filesystem (even inside a blacklisted region). This ad-hoc home directory is persistent, so it&#8217;s not like whitelisting, but even better is some scenarios.</p>
<p>Alternatively, it&#8217;s possible to blacklist everything but a certain part of a mount. That&#8217;s a bit tricky, because if a new directory appears after the rules are set, it remains unprotected. I&#8217;ll explain why below.</p>
<p>Or if that makes sense, make the entire directory tree read-only, with only a selected part read-write. That&#8217;s fine if there&#8217;s no issue with data leaking, just the possibility of malware sabotage.</p>
<p>So now to blacklisting: Firejail implements blacklisting by mounting an empty, read-only-by-root file or directory on top of the original file. And indeed,</p>
<pre>$ firejail --blacklist=delme.txt
Reading profile /etc/firejail/default.profile
Reading profile /etc/firejail/disable-common.inc
Reading profile /etc/firejail/disable-passwdmgr.inc
Reading profile /etc/firejail/disable-programs.inc

** Note: you can use --noprofile to disable default.profile **

Parent pid 30288, child pid 30289
Child process initialized in 57.75 ms
$ ls -l
<span style="color: #888888;"><em>[ ... ]</em></span>
-r--------  1 nobody nogroup     0 Jun  9 22:12 delme.txt
<span style="color: #888888;"><em>[ ... ]</em></span>
$ less delme.txt
delme.txt: Permission denied</pre>
<p>There are &#8211;noblacklist and &#8211;nowhitelist flags as well. However these merely cancel future or automatic black- or whitelistings. In particular, one can&#8217;t blacklist a directory and whitelist a subdirectory. It would have been very convenient, but since the parent directory is overridden with a whiteout directory, there is no access to the subdirectory. So each and every subdirectory must be blacklisted separately with a script or something, and even then if a new subdirectory pops up, it&#8217;s not protected at all.</p>
<p>There&#8217;s also a &#8211;read-only flag allows setting certain paths and files as read-only. There&#8217;s &#8211;read-write too, of course. When a directory or file is whitelisted, it must be flagged read-only separately if so desired (see man firejail).</p>
<h3>Mini-strace</h3>
<p>Trace all processes in the sandbox (in particular accesses to files and network). Much easier than using strace, when all we want is &#8220;which files are accessed?&#8221;</p>
<pre>$ firejail --trace</pre>
<p>And then just run any program to see what files and network sockets it accesses. And things of that sort.</p>
]]></content:encoded>
			<wfw:commentRss>http://billauer.co.il/blog/2020/06/firejail-cgroups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
