<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title><![CDATA[0xpebbles.org]]></title>
    <link><![CDATA[http://blog.0xpebbles.org]]></link>
    <description><![CDATA[0xpebbles blog]]></description>
    <lastBuildDate>Fri, 09 Apr 2021 08:37:24 +0200</lastBuildDate>
    <pubDate>Fri, 09 Apr 2021 08:37:24 +0200</pubDate>
    <language>en</language>

<!-- 20200911 -->
      <item>
      <title>Simple OpenSMTPD filter example in awk</title>
      <link>http://blog.0xpebbles.org/Simple-OpenSMTPD-filter-example-in-awk</link>
      <pubDate>11 Sep 2020 00:00:00 +0000</pubDate>
      <content:encoded><![CDATA[



<p>Turns out that <i>awk</i> lends itself very nicely to writing OpenSMTPD filters with its
line-based filter protocol. Below is a simple example of how to implement a simple DNSBL check.</p>

<p><b>Note</b>, the snippet below is an example, only, and has some shortcomings for simplicity:</p>
<ul>
<li><b>only</b> handles IPv4 addresses</li>
<li><b>does not do any version detection of the filter protocol</b>, and doesn't work on filter protocol &lt; 0.6 (which was used in OpenSMTPD &lt; 6.7; see comments in the script for details)</li>
<li>SMTP error returned on blacklisting is hardcoded, but should be configurable</li>
<li>has hardcoded logging of every filter action, people might want to silence it</li>
</ul>

<style>
<!--
pre.awk { font-family: monospace; color: #b2b2b2; background-color: #000000; }
.String { color: #8787d7; }
.Comment { color: #626262; }
.Constant { color: #87afff; font-weight: bold; }
.Special { color: #00d700; font-weight: bold; }
.Identifier { color: #ffd700; font-weight: bold; }
.Statement { color: #ff8700; font-weight: bold; }
-->
</style>

<pre class='awk'>
<span class="Comment">#!/usr/bin/awk -f</span>
<span class="Comment">#</span>
<span class="Comment"># Usage in smtpd.conf:</span>
<span class="Comment">#   filter &lt;filter-name&gt; proc-exec &quot;/path/to/filter-dnsbl &lt;resolve_cmd&gt; &lt;dnsbl&gt; &lt;ip_bl&gt;&quot;</span>
<span class="Comment">#</span>
<span class="Comment"># Where:</span>
<span class="Comment"># - &lt;resolve_cmd&gt; is a string used to resolve the DNSBL query, returning</span>
<span class="Comment">#   only the response, use %s for assembled request, escape % with %%, e.g.:</span>
<span class="Comment">#     &quot;dig +short %s&quot;</span>
<span class="Comment">#     &quot;host -t A %s | sed 's/^.*has address //'&quot;</span>
<span class="Comment"># - &lt;dnsbl&gt; is the DNSBL address-suffix to look up, e.g.:</span>
<span class="Comment">#     &quot;ix.dnsbl.manitu.net&quot;</span>
<span class="Comment"># - &lt;ip_bl&gt; is a regex, if IP(s) returned by the lookup match they are</span>
<span class="Comment">#   considered &quot;blacklisted&quot;, e.g.:</span>
<span class="Comment">#     &quot;^127\.0\.0\.[234]$&quot;</span>
<span class="Comment">#</span>
<span class="Comment"># Examples (for smtpd.conf):</span>
<span class="Comment">#   filter dnsbl_nixspam proc-exec &quot;filter-dnsbl.awk \&quot;host -t A %s | sed 's/^.*has address //'\&quot; ix.dnsbl.manitu.net '^127\.0\.0\.2$'&quot;</span>
<span class="Comment">#   filter dnsbl_nixspam proc-exec &quot;filter-dnsbl.awk \&quot;dig +short %s A\&quot; bl.spamcop.net '^127\.0\.0\.2$'&quot;</span>

<span class="Special">BEGIN</span> {
    <span class="Statement">if</span> (<span class="Special">ARGC</span> <span class="Special">!</span><span class="Special">=</span> <span class="Constant">4</span>) {
        <span class="Statement">printf</span>(<span class="String">&quot;Error, 4 args expected, got </span><span class="Special">%d</span><span class="Special">\n</span><span class="String">&quot;</span><span class="Special">,</span> <span class="Special">ARGC</span>) &gt; <span class="String">&quot;/dev/stderr&quot;</span>
        <span class="Statement">exit</span> <span class="Constant">1</span>  <span class="Comment"># note, this will terminate smtpd</span>
    }
    RESOLVE_CMD <span class="Special">=</span> <span class="Special">ARGV</span>[<span class="Special">1</span>]
    DNSBL <span class="Special">=</span> <span class="Special">ARGV</span>[<span class="Special">2</span>]
    IP_BL <span class="Special">=</span> <span class="Special">ARGV</span>[<span class="Special">3</span>]
    <span class="Special">ARGC</span> <span class="Special">=</span> <span class="Constant">0</span> <span class="Comment"># no more input args / files</span>
    <span class="Special">FS</span> <span class="Special">=</span> <span class="String">&quot;|&quot;</span>
}

<span class="String">&quot;config|ready&quot;</span> <span class="Special">==</span> <span class="Special">$0</span> {
    <span class="Statement">print</span>(<span class="String">&quot;register|filter|smtp-in|connect&quot;</span>) &gt; <span class="String">&quot;/dev/stdin&quot;</span>
    <span class="Statement">print</span>(<span class="String">&quot;register|ready&quot;</span>) &gt; <span class="String">&quot;/dev/stdin&quot;</span>
    <span class="Statement">next</span> <span class="Comment"># don't exit as this will stop smtpd</span>
}
<span class="String">&quot;filter&quot;</span> <span class="Special">==</span> <span class="Special">$1</span> {
    <span class="Statement">if</span> (<span class="Special">NF</span> &lt; <span class="Constant">9</span>) {
        <span class="Statement">printf</span>(<span class="String">&quot;Error, filter line not having enough fields, 9+ expected, got </span><span class="Special">%d</span><span class="Special">\n</span><span class="String">&quot;</span><span class="Special">,</span> <span class="Special">NF</span>) &gt; <span class="String">&quot;/dev/stderr&quot;</span>
        <span class="Statement">next</span> <span class="Comment"># don't exit as this will stop smtpd</span>
    }
    sess_id <span class="Special">=</span> <span class="Special">$6</span>
    resp_token <span class="Special">=</span> <span class="Special">$7</span>
    <span class="Comment"># reverse on the fly and trim port</span>
    <span class="Comment"># !NOTE!: with version &lt; 0.6 (e.g. $2 == &quot;0.5&quot;) the connecting ip is in $10 - not handling version detection, here</span>
    <span class="Identifier">split</span>(<span class="Special">$9</span><span class="Special">,</span> x<span class="Special">,</span> <span class="String">&quot;[.:]&quot;</span>)
    req <span class="Special">=</span> x[<span class="Special">4</span>]<span class="String">&quot;.&quot;</span>x[<span class="Special">3</span>]<span class="String">&quot;.&quot;</span>x[<span class="Special">2</span>]<span class="String">&quot;.&quot;</span>x[<span class="Special">1</span>]<span class="String">&quot;.&quot;</span>DNSBL  <span class="Comment"># !NOTE!: works only with ipv4</span>

    ret <span class="Special">=</span> <span class="String">&quot;proceed&quot;</span>
    cmd <span class="Special">=</span> <span class="Identifier">sprintf</span>(RESOLVE_CMD<span class="Special">,</span> req)
    <span class="Statement">while</span>((cmd | <span class="Statement">getline</span> r) &gt; <span class="Constant">0</span>) {
        <span class="Statement">if</span>(r <span class="Special">~</span> IP_BL) {
            ret <span class="Special">=</span> <span class="String">&quot;reject|550 connecting server is blacklisted&quot;</span>
            <span class="Statement">break</span>
        }
    }
    <span class="Identifier">close</span>(cmd)

    <span class="Statement">print</span>(sess_id<span class="String">&quot; DNSBL check: &quot;</span><span class="Special">$8</span><span class="String">&quot; [&quot;</span><span class="Special">$9</span><span class="String">&quot;]: &quot;</span>cmd<span class="String">&quot; =&gt; &quot;</span>ret) &gt; <span class="String">&quot;/dev/stderr&quot;</span>
    <span class="Statement">print</span>(<span class="String">&quot;filter-result|&quot;</span>sess_id<span class="String">&quot;|&quot;</span>resp_token<span class="String">&quot;|&quot;</span>ret) &gt; <span class="String">&quot;/dev/stdin&quot;</span>
}
</pre>


]]></content:encoded>
    </item>

<!-- 20200726 -->
      <item>
      <title>Global, static string->data associative array for a C program</title>
      <link>http://blog.0xpebbles.org/Static-associative-array-for-a-C-program</link>
      <pubDate>26 Jul 2020 00:00:00 +0000</pubDate>
      <content:encoded><![CDATA[



<p>
I pondered the question whether there is a <em>simple</em> way to have a static
(as in static lifetime) read-only associative array in C, with <b>strings as keys</b>,
mapping to any kind of data, ideally without having to manually handle its
lifetime. So, basically similar to what one would get with standard static,
const arrays, like the following:
</p>

<style type="text/css">
<!--
pre.c, pre.sh { font-family: monospace; color: #b2b2b2; background-color: #000000; }
.Type { color: #d7d787; }
.String { color: #8787d7; }
.Comment { color: #626262; }
.Constant { color: #87afff; font-weight: bold; }
.Special { color: #00d700; font-weight: bold; }
.Identifier { color: #ffd700; font-weight: bold; }
.Statement { color: #ff8700; font-weight: bold; }
-->
</style>

<pre class='c'>
<span class="Comment">// in some header</span>
<span class="Type">extern</span> <span class="Type">const</span> <span class="Type">int</span> month_days[];

<span class="Comment">// in some translation unit</span>
<span class="Type">const</span> <span class="Type">int</span> month_days[] = { <span class="Constant">31</span>, <span class="Constant">28</span>, <span class="Constant">31</span>, <span class="Constant">30</span>, <span class="Constant">31</span>, <span class="Constant">30</span>, <span class="Constant">31</span>, <span class="Constant">31</span>, <span class="Constant">30</span>, <span class="Constant">31</span>, <span class="Constant">30</span>, <span class="Constant">31</span> };
</pre>

<p>
Turns it it's not too hard, actually, at least on systems with dynamic linkers. We would need a
dynamic symbol for each entry, allowing for lookups via dlsym(3), getting back a pointer to our data.
</p>

<p>
Staying with our example above, let's say we want to lookup the same by name:
</p>

<pre class='c'>
<span class="Type">const</span> <span class="Type">int</span> month_day_jan = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_feb = <span class="Constant">28</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_mar = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_apr = <span class="Constant">30</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_may = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_jun = <span class="Constant">30</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_jul = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_aug = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_sep = <span class="Constant">30</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_oct = <span class="Constant">31</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_nov = <span class="Constant">30</span>;
<span class="Type">const</span> <span class="Type">int</span> month_day_dec = <span class="Constant">31</span>;
</pre>

<p>
Now when linking, we need to declare those symbols to be dynamic, this can be done for example with
the --dynamic-list linker flag, and a file like the following:
</p>

<pre>
{
	month_day_jan;
	month_day_feb;
	month_day_mar;
	month_day_apr;
	month_day_may;
	month_day_jun;
	month_day_jul;
	month_day_aug;
	month_day_sep;
	month_day_oct;
	month_day_nov;
	month_day_dec;
};
</pre>

<p>
Now we can do lookups like the following, for example:
</p>

<pre class='c'>
<span class="Type">int</span> x = *(<span class="Type">int</span>*)dlsym(<span class="Constant">NULL</span>, <span class="String">&quot;month_day_oct&quot;</span>);
</pre>

<p>
This is simple and straightforward, and doesn't come as a surprise - after all
this is how object files are structured and how linkers work. However, I never
considered (ab)using the dynamic linker as some sort of dynamic, associative
array lookup equivalent.
</p>

<p>
The upsides are that the data is embedded, that its lifetime
is static, that you can use strings as keys, that you don't have to do any
memory management (like fill a map at startup and free it at the end), that
dlsym(3) lookups are efficiently implemented (well, most likely at least), etc.
</p>

<p>
There are downsides, however:
</p>

<ul>
<li>the keys being symbol names are limited to alphanumeric characters and underscores, and cannot start with a number (some platforms might allow for other characters)</li>
<li>they are potentially name-mangled by the compiler (use objdump -t to check)</li>
<li>the names must be globally unique and are subject to name clashes with other unrelated symbols</li>
</ul>

<p>
Let's look at another example, embedding binary data directly, without using any C code,
by also making sure that the data is in the .rodata section, and creating the
dynamic symbol list from our object file:
</p>

<pre class='sh'>
<span class="Comment"># with LLVM's ld you might need to pass -m explicitly, e.g. -m elf_amd64</span>
ld <span class="Special">-r</span> <span class="Special">-b</span> binary <span class="Special">-o</span> bins.o file1.png folder_x/otherfile.txt
objcopy <span class="Special">--rename-section</span> .<span class="Identifier">data</span>=.rodata,contents,alloc,load,readonly bins.o
<span class="Comment"># generate dynamic symbol list</span>
nm bins.o | awk <span class="Statement">'</span><span class="String">BEGIN{print &quot;{&quot;}{print $3&quot;;&quot;}END{print &quot;};&quot;}</span><span class="Statement">'</span> <span class="Statement">&gt;</span> bins.symlst
</pre>

<p>
This will actually create 3 symbols per file, with a filename-based symbol name
and some prefix and suffixes, all pretty self explanatory:
</p>

<pre>
_binary_file1_png_end
_binary_file1_png_size
_binary_file1_png_start
_binary_folder_x_otherfile_txt_end
_binary_folder_x_otherfile_txt_size
_binary_folder_x_otherfile_txt_start
</pre>

]]></content:encoded>
    </item>

<!-- 20190817 -->
      <item>
      <title>PowerVR SGX on the BeagleBone Black in 2019</title>
      <link>http://blog.0xpebbles.org/PowerVR-SGX-on-the-beaglebone-black-in-2019</link>
      <pubDate>17 Aug 2019 00:00:00 +0000</pubDate>
      <content:encoded><![CDATA[



<p>
Since I spent way too much time on figuring this out, confused by plenty of old and outdated online
sources, here is how one would get the PowerVR SGX driver running on a current
Linux in 2019 - in this case a debian 9.6 with a 4.4 kernel. Other combinations
might/should work also, but I have not tested them.
</p>

<p>
To summarize briefly, the difference to the previous ways of getting the SGX
stuff running, is that the old <em>GFX_SDK_*</em> based setups are outdated. This
includes <em>omaplfb.ko</em> kernel module based instructions, which also come from the
<em>GFX_SDK_*</em> times.
Last but not least, it looks like one has to run a <em>TI kernel</em> (updated
to with flag --ti-kernel, see below), as the <em>bone kernel</em>s (--bone-kernel)
don't seem to have the new SGX driver stack.
</p>

<p>
I used <a href="https://rcn-ee.com/rootfs/2018-12-10/microsd/bone-debian-9.6-console-armhf-2018-12-10-2gb.img.xz">bone-debian-9.6-console-armhf-2018-12-10-2gb.img.xz</a> from RobertCNelson's
site at <a href="https://rcn-ee.com/rootfs/2018-12-10/microsd/">https://rcn-ee.com/rootfs/2018-12-10/microsd/</a>, as I wanted a leaner
base system than what's available on <a href="https://beagleboard.org/latest-images">https://beagleboard.org/latest-images</a>.
</p>

<p>
To put it in a nutshell, we need to run a TI kernel, and install the matching
SGX DDK, and ideally initialize it on startup. So on your system on the BBB
the following should install the TI kernel (v4.4, which worked for me) - the below assumes
that the default user <em>debian</em> of the image is used, so some sudo is needed occasionally:
</p>

<style type="text/css">
<!--
pre.sh { font-family: monospace; color: #dadada; background-color: #000000; }
.shShellVariables { color: #87afff; }
.Comment { color: #626262; }
.Constant { color: #87afff; font-weight: bold; }
.Special { color: #00d700; font-weight: bold; }
.String { color: #8787ff; }
.Statement { color: #ff8700; font-weight: bold; }
-->
</style>

<pre class="sh">
<span class="Statement">cd</span> /opt/scripts/tools

<span class="Comment"># install TI kernel, this also installs the matching SGX drivers</span>
git pull                                       <span class="Comment"># fetch latest revisions of kernels to upgrade to</span>
sudo ./update_kernel.sh <span class="Special">--ti-kernel</span> <span class="Special">--lts-4_4</span>  <span class="Comment"># if branch not there anymore, make sure whatever branch is used contains a working pvrsrvkm.ko</span>
sudo reboot
</pre>

<p>
Now the SGX DDK, which we'll build from source:
</p>

<pre class="sh">
<span class="Comment"># some libs for later</span>
sudo apt install <span class="Special">-y</span> libdrm-omap1 libgbm1

<span class="Comment"># get the SGX DDK for userland libraries, demos and tools needed to initialize PowerVR</span>
<span class="Comment"># NOTE: the branch used below has to match kernel version, change if using different kernel above</span>
<span class="Statement">cd</span> ~
git clone <span class="Special">-b</span> ti-img-sgx/<span class="Constant">1</span>.<span class="Constant">14</span>.3699939_k4.<span class="Constant">4</span> git://git.ti.com/graphics/omap5-sgx-ddk-um-linux.git <span class="Special">--depth=1</span>
<span class="Statement">cd</span> omap5-sgx-ddk-um-linux/
sudo env <span class="Identifier">DISCIMAGE</span>=/ <span class="Identifier">TARGET_PRODUCT</span>=ti335x make install
<span class="Statement">cd</span> ~
<span class="Statement">rm</span> <span class="Special">-rf</span> ./omap5-sgx-ddk-um-linux

<span class="Comment"># hackfix needed missing reference to libgbm.so.2</span>
sudo ln <span class="Special">-s</span> /usr/lib/arm-linux-gnueabihf/libgbm.so.<span class="Constant">1</span> /usr/lib/arm-linux-gnueabihf/libgbm.so.<span class="Constant">2</span>

<span class="Comment"># verify driver loaded - should show pvrsrvkm</span>
lsmod | <span class="Statement">grep</span> pvr

<span class="Comment"># verify, there should be some info like &quot;[drm] Initialized&quot; and &quot;PVR_K: UM DDK...&quot; infos</span>
dmesg | <span class="Statement">grep</span> <span class="Special">-i</span> <span class="Special">-C</span>1 <span class="Statement">'</span><span class="String">drm\|sgx\|pvr</span><span class="Statement">'</span>

<span class="Comment"># set mode SGX should work in - at this point there are three installed, but</span>
<span class="Comment"># only one that works, as the libpvrws_WAYLAND.so and libpvrGBMWSEGL.so are</span>
<span class="Comment"># both for DRM/WAYLAND based multi-window systems and weston isn't installed.</span>
<span class="Comment"># According to the docs there also should be libpvrDRMWSEGL_FRONT.so, a no-vsync</span>
<span class="Comment"># and thus faster version of libpvrDRMWSEGL.so.</span>
<span class="Comment"># Other options like pixel format can also be set to RGB565, RGB888 or ARGB8888,</span>
<span class="Comment"># select the one that works for you (colors might be swapped for 565 or 888, depending</span>
<span class="Comment"># on LCD wiring, see TI's AM335x silicon errata.</span>
sudo <span class="Statement">rm</span> /etc/powervr.ini
sudo tee <span class="Special">-a</span> /etc/powervr.ini <span class="Statement">&lt;&lt;EOF</span>
<span class="String">[default]</span>
<span class="String">WindowSystem=libpvrDRMWSEGL.so</span>
<span class="String">DefaultPixelFormat=RGB888</span>
<span class="Statement">EOF</span>

<span class="Comment"># init powervr for testing, will be automated later, below</span>
sudo /usr/bin/pvrsrvctl <span class="Special">--start</span> <span class="Special">--no-module</span>

<span class="Comment"># verify via tools shipped in the omap5-sgx-ddk:</span>
<span class="Statement">cd</span> /usr/bin   <span class="Comment"># b/c gles2test1 depending on that pwd for shader files in /usr/bin/</span>
eglinfo       <span class="Comment"># should spit out a lot of things</span>
gles1test1 x  <span class="Comment"># shows some spinning triangles on green background (arg is num_frames it should run I guess, non-integer args make it run forever)</span>
gles2test1 x  <span class="Comment"># similar but on purple backgroun (see above for dummy arg x) - if red background check powervr.ini's pixel format we set above</span>
<span class="Statement">cd</span> -

<span class="Comment"># more info about SGX chip if needed</span>
<span class="Statement">cat</span> /proc/pvr/version
</pre>

<p>
If the above installed fine, and all the test steps in the above block also
worked, let's automate the SGX initialization at startup via systemd:
</p>

<pre class="sh">
<span class="Comment"># service script starting PowerVR environment</span>
sudo tee <span class="Special">-a</span> /etc/systemd/system/pvr-init.service <span class="Statement">&lt;&lt;&quot;TTT&quot;</span>
<span class="String">[Unit]</span>
<span class="String">Description=PowerVR</span>
<span class="String">After=multi-user.target</span>
<span class="String">[Service]</span>
<span class="String">Type=oneshot</span>
<span class="String">RemainAfterExit=yes</span>
<span class="String"># startup fails sometimes (too early?), retry in loop - this paired with TimeoutStartSec is a</span>
<span class="String"># workaround to oneshot services refusing decent Restart= settings (at least for systemd &lt;= 232)</span>
<span class="String">ExecStart=/bin/sh -c 'while ! /etc/init.d/rc.pvr start; do sleep 5; done'</span>
<span class="String">ExecStop=/etc/init.d/rc.pvr stop</span>
<span class="String">TimeoutStartSec=60sec</span>
<span class="String">User=root</span>
<span class="String">[Install]</span>
<span class="String">WantedBy=multi-user.target</span>
<span class="Statement">TTT</span>

sudo systemctl enable pvr-init

<span class="Comment"># done</span>
sudo reboot
</pre>

]]></content:encoded>
    </item>

<!-- 20190616 -->
      <item>
      <title>FreeBSD 12 on the 51nb x210</title>
      <link>http://blog.0xpebbles.org/FreeBSD-12-on-the-51nb-x210</link>
      <pubDate>16 Jun 2019 00:00:00 +0000</pubDate>
      <content:encoded><![CDATA[



<p>
The x210 is a x201 thinkpad chassis with modern hardware inside, from a group of
chinese hardware modders that started out doing screen upgrades, originally.
Depending on the production batches they run and probably the chassis they have
available the hardware might differ slightly from machine to machine.
The <a href="http://www.cnmod.cn/">group's blog</a> has more info on the
batches, different devices, BIOS updates, etc.. A few notes about the hardware
first, before talking about FreeBSD on the one I got:
</p>

<h3>Hardware Notes</h3>

As said, the hardware depends on the batch, some special runs they sometimes
do, and the chassis used (one can also buy just the board alone). E.g. the
laptop I got does have a Core i5-8250U inside (there are i7 versions, too) and
was in a chassis that came with a default palmrest (no touchpad, but some
others seem to have been shipped with one). It has a WUXGA (1920x1200) display
which is physically actually slightly bigger than the chassi's screen bezel.
</p>

<p>
Since I did want a touchpad (I guess I could've asked them directly, so my bad)
I bought a used palmrest. There are two types for x201* machines that aren't
compatible with each other, grouped as 25W and 35W models with different
connectors, full list <a href="https://support.lenovo.com/es/en/solutions/migr-70510">here</a>
(I needed a 35W one and specifically replaced FRU 60Y5414 with FRU 60Y5415). Turns
out that in order to make the touchpad palmrest fit, some clipping was needed
as the mainboard's m.2 port and another part won't fit otherwise. Some plastic
and metal needs to be removed on both sides of the touchpad, so one before and
two after pictures:
</p>

<div style="clear:both;display:inline-block">
<a href="/media/60Y5415-before.jpg"><img src="/media/60Y5415-before_s.jpg" alt="FRU 60Y5415 before modification" class="thumbnail_l"/></a>
<a href="/media/60Y5415-after-l.jpg"><img src="/media/60Y5415-after-l_s.jpg" alt="FRU 60Y5415 after modification (left)" class="thumbnail_l"/></a>
<a href="/media/60Y5415-after-r.jpg"><img src="/media/60Y5415-after-r_s.jpg" alt="FRU 60Y5415 after modification (right)" class="thumbnail_l"/></a>
</div>

 

<h2>Running FreeBSD 12</h2>

<h3>Graphics and Screen</h3>

<h4>General</h4>

<p>
You'll need FreeBSD 12 for the graphics, I originally tried to make it work on
FreeBSD 11.2, but didn't manage to get it to work.
</p>

<p>
The processor has an <em>Intel UHD Graphics 620</em> integrated GPU. You'll
need to install the <b>graphics/drm-kmod</b> port. Make sure to read the post
install message! E.g. you'll need to add all users that need graphics to the
'video' group, and also put the following in /etc/rc.conf (more infos
<a href="https://wiki.freebsd.org/Graphics">here</a>):
</p>

<pre>
kld_list="/boot/modules/i915kms.ko"
</pre>

<p>
I had some initial problems with the console, but I don't fully remember what.
Either way, setting the following in /boot/loader.conf helped and also gave me
a hires console:
</p>

<pre>
kern.vty=vt
kern.vt.fb.default_mode="1920x1200"
</pre>

<h4>X11 / xorg.conf</h4>

<p>
The <a href="https://wiki.freebsd.org/Graphics">FreeBSD Graphics wiki</a>
suggests that one "should <b>not</b> have to prepare an xorg.conf configuration
file" and that "Xorg should autodetect the driver and utilize the
<a href="https://www.x.org/wiki/ModeSetting/">modesetting</a> Xorg driver and
<a href="https://www.freedesktop.org/wiki/Software/Glamor/">glamor</a> driver".
</p>

<p>
However, this <u>did not work</u> for me on this machine. The autodetection
used the <em>intel</em> driver with <em>uxa</em> as acceleration method, which
was slow and buggy. Not having read carefully the wiki that states clearly that
the autodetection "should [...] utilize the <b>modesetting</b> Xorg driver and
<b>glamor</b> driver", I did switch the acceleration from <em>uxa</em> to
<em>sna</em>, first. This improved the situation by a lot, however some
artefacts remained and X11 froze from time to time (which I was able to
unfreeze by switching to the vt console and back).<br>
Anyways, what was really needed (and works really well) was a custom xorg.conf
that sets the modesetting driver with glamor as acceleration method,
explicitly. So I let <em>X -configure</em> create an xorg.conf template for me
and then specified explicitly in <em>Section "Device"</em>:
</p>

<pre>
Driver  "modesetting"
Option  "AccelMethod" "glamor"
</pre>

<h4>Screen Size</h4>

<p>
As mentioned above, the physical screen size is a tiny bit bigger than the
chassi's bezel. I simply reduced the usable screen area a bit via the window
manager. I use <b>x11-wm/spectrwm</b> which has a <em>region</em> feature,
which allowed me to do that easily. In the end I have a usable region of
1912x1194 pixels, losing 8 pixels on the right, 3 on top and 3 on the bottom.
So the needed spectrwm config entry in this specific case would be:
</p>

<pre>
region = screen[1]:1912x1194+0+3
</pre>

<p>
If not having such support from the wm, one could register and use a new
modeline via xrandr. I did that first, and it works, but I didn't figure out
how to specifically tell it where the screen should start, it was always
anchored in the top left corner.
</p>
<p>
Alternatively, one could also file off some plastic of the bezel, to make use
of the full screen.
</p>

<h4>Screen Brightness</h4>

<p>
The brightness buttons don't work out of the box, and things like kldloading
acpi_ibm(4) won't help - this isn't actually a thinkpad after all. Using
<b>graphics/intel-backlight</b> does not help either, as the GPU doesn't
control the brightness (in contrast to for example the x201), but the embedded
controller does. Poking around the ACPI tables (<em>acpidump -dt</em>) made me quickly
find an already existing method <em>\_SB.PCI0.GFX0.DD1F._BCM</em> that can be
used to set <em>\_SB.PCI0.LPCB.EC0.BKLG</em>, which controls the brightness
levels. So using <b>sysutils/acpi_call</b> we can run (after kldloading
acpi_call first):
</p>

<style type="text/css">
<!--
pre.sh { font-family: monospace; color: #dadada; background-color: #000000; }
.shShellVariables { color: #87afff; }
.Comment { color: #626262; }
.Constant { color: #87afff; font-weight: bold; }
.Special { color: #00d700; font-weight: bold; }
.String { color: #8787ff; }
-->
</style>
<pre class="sh">
acpi_call <span class="Special">-p</span> <span class="String">'\_SB.PCI0.GFX0.DD1F._BCM'</span> <span class="Special">-i</span> <span class="shShellVariables">$VAL</span>   <span class="Comment"># 0 <= $VAL <= 15</span>
</pre>

<p>
The predefined 16 brightness levels are not ideal, 0 is still way brighter than
what you would get from other laptops. The good news is that those levels can
be adjusted by apparently patching the EC firmware (more info
<a href="https://forum.thinkpads.com/viewtopic.php?t=128267">here</a>), however
I haven't done so, myself, though.
</p>

<p>
I also have not looked into hooking up the brightness buttons out of laziness,
but simply wrapped the acpi_call based control above in a convenience script.
</p>


<h3>Sound</h3>

<p>
Seems to work fine out of the box using snd_hda(4). However, in order for the
sound to automatically switch over to the headphone jack when something gets
plugged in, I needed the following in /boot/device.hints:
</p>

<pre>
hint.hdaa.0.nid31.config="as=4 seq=0 device=Speaker"
hint.hdaa.0.nid25.config="as=4 seq=15 device=Headphones"
</pre>

<p>
I looked up the nid numbers needed from the output of <em>sysctl dev.hdaa</em>.
</p>

<p>
The volume buttons I hooked up myself by making use of the XF86 multimedia keys
XF86AudioRaiseVolume and XF86AudioLowerVolume. Since I'm using
<b>x11-wm/spectrwm</b>, as mentioned above, the according spectrwm config
entries would be something along those lines (with some bonus key combinations
to control treble and bass, given we had to bind those buttons manually
anyways):
</p>

<pre>
program[raise_volume]  = mixer vol +2 pcm +2
program[lower_volume]  = mixer vol -2 pcm -2
program[raise_treble]  = mixer treble +5
program[lower_treble]  = mixer treble -5
program[raise_bass]    = mixer bass +5
program[lower_bass]    = mixer bass -5
bind[raise_volume]     = XF86AudioRaiseVolume
bind[lower_volume]     = XF86AudioLowerVolume
bind[raise_treble]     = Control+XF86AudioRaiseVolume
bind[lower_treble]     = Control+XF86AudioLowerVolume
bind[raise_bass]       = Shift+XF86AudioRaiseVolume
bind[lower_bass]       = Shift+XF86AudioLowerVolume
</pre>

<p>
The downside of making use of XF86 multimedia keycodes is that this now only
works in X, of course.
</p>


<h3>WiFi</h3>

<p>
My machine came with a Broadcom BCM4352 802.11ac Mini PCIe WiFi card, for which
there is no driver support at the time of writing. So I replaced it with
another one. Contrary to stock/regular Thinkpads (and laptops in general), the
BIOS the x210 comes with doesn't do any wifi card whitelisting, so swapping out
the card doesn't require any extra work.
</p>


<h3>Webcam</h3>

<p>
The laptop I got also had a webcam installed (from Chicony Electronics), which
shows up as a USB device and works using <b>multimedia/webcamd</b>. For
example, to test it quickly, make sure <em>cuse</em> is kldloaded, then:
</p>

<pre class="sh">
service webcamd onestart <span class="shShellVariables">$DEV</span>  <span class="Comment"># where $DEV is the camera's USB device, e.g. ugen0.2</span>
mplayer tv:// <span class="Special">-tv</span> driver=v4l:width=320:height=240:device=/dev/video0 <span class="Special">-fps</span> <span class="Constant">25</span>
</pre>

<p>
The camera supports in my case the following resolutions: QVGA (320x240), VGA
(640x480), SVGA (800x600), XGA (1024x768), WXGA (1280x800), SXGA (1280x1024)
</p>


<h3>Other</h3>

<ul>
<li>I did not test the modem, microphone jack or the external mini display port so
far.</li>
<li>I did dump the contents of the flash chip using a
<a href="http://dangerousprototypes.com/docs/Bus_Pirate">BusPirate</a>, which
worked fine. Eventually I want to try flashing coreboot, but haven't done so,
yet. No flash write protection seems to be active, so internal flashing could
be used, I guess.</li>
<li>The machine is mostly silent, the fan starts when there is some decent load,
but other than that it doesn't even spin at all and the machine also doesn't
get hot either (around 45°C for idly use).</li>
<li>Suspend to RAM or disk doesn't seem to work, the graphics driver freezes while
trying to suspend and the machine hangs at that point. Maybe a future update
will fix this.</li>
<li>Thinklight and numlock work, but those work without OS support, anyways.</li>
<li>Also, as with the brightness buttons, other Fn-buttons aren't wired up,
either.</li>
<li>I don't have any data to compare the x210's battery life with, but compared to
my x201i it improved greatly. On a 3 year old, already well degraded 9-cell
battery that didn't run the x201i for more than a good hour, this machine gets
4h out of it. I'm not sure what a new battery would yield, but given what I had
before, I'm super happy.</li>
</p>
<p>
<b>UPDATE (2019-10-09):</b> A brand new 9-cell battery with 7800mAh seems to
run this machine for nearly 10h (for light use, e.g. reading stuff, writing
mails, etc.). This is way more than what I actually hoped for.
</p>


]]></content:encoded>
    </item>

<!-- 20190314 -->
      <item>
      <title>The (sorry) state of the www</title>
      <link>http://blog.0xpebbles.org/The-sorry-state-of-the-www</link>
      <pubDate>14 Mar 2019 00:00:00 +0000</pubDate>
      <content:encoded><![CDATA[



<p>
The web today isn't the way more content-centric and naive-but-simple web we
used to have in the 90s and early 2000s, but has developed a much stronger
focus on tracking and trying to influence what people think instead of being a
source of more or less freely and actively shared information. Additionally,
a lot of sites seem to care today more about presentation than content,
resulting in many shiny, but bloated and less useful sites.
</p>

<p>
The bloat is comical sometimes; even heavily used sites that would benefit
directly from leaner approaches somehow find it normal to use insane amounts of
resources, leading to pointlessly increased traffic, CPU load, energy
consumption and ultimately carbon footprint. e.g. a standard slack web chat
session with no more than 50 users easily uses up 250-500MB of RAM (in addition to
the already heavy browser requirements). Loading slack on my laptop takes
longer than booting the OS. I find it hard to justify the need for this kind of
bloat for a chat. We talk about exchanging a few bytes of text between people
in real time, with optional message history, something we do for 30+ years on
way less beefy machines.
</p>

<p>
Also, more and more gets centralized, distributed and managed by a few big
players in the field, who additionally make it hard for independent services
to exist. This same centralization happens for other common, non-web services:
for example, running your own mailserver today is more often than not a
constant battle to not be blacklisted as a spam source, because many
relays just consider @gmail.com and other big ones as the only trustworthy
sender domains (which is ironic at best), no matter how clean your record is,
how careful you set up everything for spam heuristics (like PTR records, DKIM,
etc.).
</p>

<p>
Shining through in all paragraphs above is a feeling that seems to underlie
this all, namely it all haven gotten more and more about power. In some areas
it surely always was somewhere about power, but from the end user perspective
it is so much more invasive now, and the content so much more shallow by
average, and the positive enthousiasm over this big pool of information of the
early web is now either gone or comes with a bitter after-taste.
</p>

<p>
Not to mention that there are so many things with the web that are broken to
begin with, its tech's ever growing complexity will always be error prone,
leading to all kinds of vulnerabilities, breaches and scams. Its one way
links will always break eventually leading to frustration, and not to mention
all the resources and energy wasted by all the useless bloat of the nowadays
rapid-development web frameworks and often intentional content-hiding style.
</p>

<p>
I don't seem to be the only one that is worried about this development so
here's a collection of links looking at this from plenty of different angles:
</p>

<ul>
<li><a href="https://medium.com/@giacomo_59737/the-web-is-still-a-darpa-weapon-31e3c3b032b8" target="_blank">The Web is still a DARPA weapon.</a> - click-baity title, but interesting reflection of power use and influence on the web</li>
<li><a href="https://gopher.floodgap.com/overbite/relevance.html" target="_blank">Why is Gopher Still Relevant?</a> - overview of gopher in contrast to the web, which experiences some renewed interest b/c of it's structured, minimalist content-centricness</li>
<li><a href="https://en.wikipedia.org/wiki/Project_Xanadu" target="_blank">Project Xanadu</a> - Ted Nelson is still around and his vision feels IMHO fresher than the current web</li>
<li><a href="https://nrempel.com/posts/what-we-have-now-is-not-advertising/" target="_blank">What We Have Now Is Not Advertising</a> - reflections on targeted advertising</li>
<li><a href="https://mg.guelker.eu/saverss/" target="_blank">Save RSS and Atom!</a> - arguments for assuring content-centricness, choice and privacy for consumption of web-content (it's sad that RSS/Atom were necessary to begin with)</li>
<li><a href="https://pxlnv.com/blog/bullshit-web/" target="_blank">The Bullshit Web</a> - reflections on web-bloat in interesting depth</li>
<li><a href="/media/2018-03-02-death-of-transit.pdf" target="_blank">The Death of Transit and Beyond</a> - super interesting presentation about content providers longing for even more power and getting into controlling more and more of the worldwide transit, with very spot on historical comparison to the "Gilded Age"</li>
<li><a href="http://fabiensanglard.net/bloated/index.html" target="_blank">Bloated</a> - more reflections on bloat</li>
<li><a href="http://tonsky.me/blog/disenchantment/" target="_blank">Software disenchantment</a> - even more about bloat, not only about the web, nicely put into perspective</li>
<li><a href="https://www.reinterpretcast.com/open-hypermedia" target="_blank">Freeing the Web from the Browser</a> - ideas on better/less-broken hypermedia designs, also an intro to a <a href="https://www.reinterpretcast.com/pdfs/savage-j-dissertation-2018-05.pdf" target="_blank">comprehensive dissertation</a> from the same author</li>
<li><a href="https://en.wikipedia.org/wiki/Solid_(web_decentralization_project)" target="_blank">Solid (web decentralization project)</a> - the <em>father of the web</em> himself seems to see a need for change to go back to more decentralization and privacy</li>
<li><a href="https://indieweb.org/" target="_blank">IndieWeb</a> - calls for a less corporate centric web</li>
<li><a href="https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website.html" target="_blank">How to Build a Low-tech Website?</a> - call for less bloat with interesting example (also good suggestions and plenty more links in the comments)</li>
<li><a href="https://learnbchs.org/index.html" target="_blank">BCHS stack</a> - fast, secure and low-level web stack: less bloat, less complexity, less error prone black/hidden magic (see <a href="https://learnbchs.org/easy.html" target="_blank">example</a>)</li>
<li><a href="https://en.wikipedia.org/wiki/Lo_and_Behold,_Reveries_of_the_Connected_World" target="_blank">Lo and Behold, Reveries of the Connected World</a> - documentary by Werner Herzog, with Ted Nelson</li>
<li><a href="http://weboob.org/" target="_blank">weboob.org - Web outside of browsers/</a> - project from people that want features and not the presentation overhead of websites</li>
<li><a href="http://cryto.net/~joepie91/blog/2016/07/14/cloudflare-we-have-a-problem/ target="_blank">CloudFlare, We Have A Problem</a> - thoughts on Cloudflare and its centralization (also as MitM actor), it encouraging bad practices as a business model, ...</li>
<li><a href="https://www.slashgeek.net/2016/05/17/cloudflare-is-ruining-the-internet-for-me/ target="_blank">CloudFlare is ruining the internet (for me)</a> - CF rant from a cultural perspective</li>
<li><a href="https://idlewords.com/talks/website_obesity.htm" target="_blank">The Website Obesity Crisis</a> - slides of a talk about bloat</li>
<li><a href="https://gemini.circumlunar.space/docs/specification.html" target="_blank">Project Gemini</a> - Gopher inspired client-server protocol for hypertext, with simplicity as goal</li>
</ul>

<p>
Another worrisome thing going on, IMHO, is the push by many of the big players for
DNS-over-HTTPS (DOH). They seem to propagate the claim that this is needed because
DNS is insecure. Although a valid point at the time of writing, they ignore the
fact that the latter is addressed by things like dnscrypt with DNSSEC. Besides the
fact that pushing operating system level services like a name resolver into an
application (e.g. a browser, where you would for example set the DoH resolver
in Firefox via config option network.trr.uri) is insane to begin with, they seem
to have strong reasons to push for DoH, probably motivated again by power and
tracking reasons. Why wouldn't they be interested in overriding the globally by
default decentralized ISP provided resolvers (which most peoples' system would
get via DHCP if not overridden), and instead getting a grip on the majority of
all DNS lookups by sending them by default to one or a few big players? Data is
money after all. I don't want to even think about the massive single point of
failure such a centralization would also be.
</p>

<p>
There are claims that this would somehow free you from those apparently evil
ISPs that censor your requests. Sure, this might happen (as is the case with
kinda every coffee shop or hotel uplink), but they don't mention how tasty it
would be for them to resolve things for you that bypass your OS-level resolver,
where you could setup per-domain blacklists to block trackers, adservers,
malicious stuff, etc..
</p>

<p>
Wouldn't it be too nice for companies like Cloudflare to receive in a
centralized way a major number of name lookups, by being the default resolver
in one or more of the already few major browsers? Would you trust this US
company, that already encourages people to give them their certificates to play
man-in-the-middle, to know more about your browsing habits? Would you trust Google
with their Chrome browser having even more insight into your live (and control
over what you can access), but defaulting Chrome to use their resolvers? What a
coincidence that that's a company that makes money by tracking you for targeted
advertising... not. A quote that reflects my worries from the comments under
<a href="https://hacks.mozilla.org/2018/05/a-cartoon-intro-to-dns-over-https/" target="_blank">this DoH intro</a>:
</p>

<blockquote>
Brett Glass: So, Mozilla intends to hack users' DNS, redirecting their queries
away from their ISPs (which are trustworthy and with which they have a business
relationship) to an untrustworthy VPN vendor - Cloudflare. Those users are not
Cloudflare's customers, and so the only way Cloudflare can monetize this
service is to spy on users and sell their personal information. In short,
Mozilla is supporting, aiding, and abetting privacy invasion - probably in
exchange for money from Cloudflare. Not only unethical but probably actionable
by the FTC.
</blockquote>

<p>
Some links specifically about DoH and the debate around it:
</p>

<ul>
<li><a href="https://www.theregister.co.uk/2018/10/23/paul_vixie_slaps_doh_as_dns_privacy_feature_becomes_a_standard/" target="_blank">The inmates have taken over the asylum</a> - co-architect of the DNS, Paul Vixie, having a strong opinion about this development; the <a href="https://forums.theregister.co.uk/forum/all/2018/10/23/paul_vixie_slaps_doh_as_dns_privacy_feature_becomes_a_standard/" target="_blank">comments</a> are also interesting</li>
<li><a href="https://dzone.com/articles/pros-and-cons-of-dns-over-https" target="_blank">Pros and Cons of DNS Over HTTPS</a> - trying to reflect on the pros and cons, but IMHO falling short in many areas</li>
<li><a href="https://www.ghacks.net/2018/03/20/firefox-dns-over-https-and-a-worrying-shield-study/" target="_blank">Firefox, DNS over HTTPS and a controversial Shield Study</a> - interesting article about mozilla's DoH study in Firefox with critical voices from within mozilla</li>
<li><a href="https://blog.apnic.net/2019/04/15/opinion-clarifying-what-doh-means-for-privacy/" target="_blank">Opinion: Clarifying what DoH means for privacy</a> - APNIC's Geoff Huston and his view on DoH, based on his vast and long experience</li>
</ul>

<p>
To me this feels like it's all in line with the "Death of Transit" presentation
linked to above in the first bullet point list: another worrisome development
mainly supported by some internet megacorps longing for even more centralization
and control.
</p>

<p>
<em>As a closing line to avoid misinterpretation: my intro text as well as the
articles in the first bullet point list are about the web as a content source,
and not about the web's reinvention of the thin-client/mainframe model, which
is what webapps basically are.</em>
</p>

<p>
<b>UPDATE (2019-06-03):</b> Added a detailed and interesting opinion article to the DoH article list<br>
<b>UPDATE (2021-03-17):</b> Added some more links<br>
</p>

]]></content:encoded>
    </item>


  </channel>
</rss>

