<?xml version="1.0" encoding="iso-8859-1"?>
<!-- name="generator" content="pyblosxom/1.5.3" -->
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">

<rss version="0.91">
<channel>
<title>Kristof's complaints</title>
<link>http://www.sigsegv.be/blog</link>
<description>Because there aren't enough idiots on the Internet already.</description>
<language>en</language>
<item>
  <title>PR 219251</title>
  <link>http://www.sigsegv.be/blog/freebsd/PR219251.html</link>
  <description>

&lt;p&gt;
As I threatened to do in my previous post, I&#x27;m going to talk about
&lt;a href=&quot;https:&#x2F;&#x2F;bugs.freebsd.org&#x2F;bugzilla&#x2F;show_bug.cgi?id=219251&quot;&gt;PR
219251&lt;&#x2F;a&gt; for a bit.

The bug report dates from only a few months ago, but the first report (that I
can remeber) actually came from Shawn Webb on &lt;a
href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;lattera&#x2F;status&#x2F;833809837247045636&quot;&gt;Twitter, of all
places&lt;&#x2F;a&gt;:

&lt;img src=&quot;&#x2F;images&#x2F;PR219251.png&quot; alt=&quot;backtrace&quot; width=&quot;512&quot; height=&quot;288&quot; &#x2F;&gt;

&lt;p&gt;
Despite there being a stacktrace it took quite a while (nearly 6 months in
fact) before I figured this one out.
&lt;&#x2F;p&gt;

&lt;p&gt;
It took Reshad Patuck managing to distill the problem down to a small-ish test
script to make real progress on this.
His testcase meant that I could get core dumps and experiment. It also
provided valuable clues because it could be tweaked to see what elements were
required to trigger the panic.
&lt;&#x2F;p&gt;

&lt;p&gt;
This test script starts a (vnet) jail, adds an epair interface to it, sets up pf
in the jail, and then reloads the pf rules on the host. Interestingly the
panic does not seem to occur if that last step is not included.
&lt;&#x2F;p&gt;

&lt;p&gt;
Time to take a closer look at the code that breaks:
&lt;&#x2F;p&gt;

&lt;pre class=&quot;sh_cpp&quot;&gt;
u_int32_t
pf_state_expires(const struct pf_state *state)
{
        u_int32_t       timeout;
        u_int32_t       start;
        u_int32_t       end;
        u_int32_t       states;

        &#x2F;* handle all PFTM_* &gt; PFTM_MAX here *&#x2F;
        if (state-&gt;timeout == PFTM_PURGE)
                return (time_uptime);
        KASSERT(state-&gt;timeout != PFTM_UNLINKED,
            (&quot;pf_state_expires: timeout == PFTM_UNLINKED&quot;));
        KASSERT((state-&gt;timeout &lt; PFTM_MAX),
            (&quot;pf_state_expires: timeout &gt; PFTM_MAX&quot;));
        timeout = state-&gt;rule.ptr-&gt;timeout[state-&gt;timeout];
        if (!timeout)
                timeout = V_pf_default_rule.timeout[state-&gt;timeout];
        start = state-&gt;rule.ptr-&gt;timeout[PFTM_ADAPTIVE_START];
        if (start) {
                end = state-&gt;rule.ptr-&gt;timeout[PFTM_ADAPTIVE_END];
                states = counter_u64_fetch(state-&gt;rule.ptr-&gt;states_cur);
        } else {
                start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START];
                end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END];
                states = V_pf_status.states;
        }
        if (end &amp;&amp; states &gt; start &amp;&amp; start &lt; end) {
                if (states &lt; end)
                        return (state-&gt;expire + timeout * (end - states) &#x2F;
                            (end - start));
                else
                        return (time_uptime);
        }
        return (state-&gt;expire + timeout);
}
&lt;&#x2F;pre&gt;

&lt;p&gt;
Specifically, the following line:

&lt;pre class=&quot;sh_cpp&quot;&gt;
	states = counter_u64_fetch(state-&gt;rule.ptr-&gt;states_cur);
&lt;&#x2F;pre&gt;

&lt;p&gt;
We try to fetch a counter value here, but instead we dereference a bad
pointer. There&#x27;s two here, so already we need more information.  Inspection
of the core dump reveals that the state pointer is valid, and contains sane
information. The rule pointer (rule.ptr) points to a sensible location, but
the data is mostly 0xdeadc0de. This is the memory allocator being helpful (in
debug mode) and writing garbage over freed memory, to make use-after-free bugs
like this one easier to find.
&lt;&#x2F;p&gt;

&lt;p&gt;
In other words: the rule has been free()d while there was still a state
pointing to it. Somehow we have a state (describing a connection pf knows
about) which points to a rule which no longer exists.
&lt;&#x2F;p&gt;

&lt;p&gt;
The core dump also shows that the problem always occurs with states and rules
in the default vnet (i.e. the host pf instance), not one of the pf instances
in one of the vnet jails. That matches with the observation that the test
script does not trigger the panic unless we also reload the rules on the host.
&lt;&#x2F;p&gt;

&lt;p&gt;
Great, we know what&#x27;s wrong, but now we need to work out how we can get into
this state. At this point we&#x27;re going to have to learn something about how
rules and states get cleaned up in pf. Don&#x27;t worry if you had no idea, because
before this bug I didn&#x27;t either.
&lt;&#x2F;p&gt;

&lt;p&gt;
The states keep a pointer to the rule they match, so when rules are changed
(or removed) we can&#x27;t just delete them. States get cleaned up when connections
are closed or they time out. This means we have to keep old rules around until
the states that use them expire.
&lt;&#x2F;p&gt;

&lt;p&gt;
When rules are removed pf_unlink_rule() adds then to the V_pf_unlinked_rules
list (more on that funny V_ prefix later). From time to time the pf purge
thread will run over all states and mark the rules that are used by a state.
Once that&#x27;s done for all states we know that all rules that are not marked as
in-use can be removed (because none of the states use it).
&lt;&#x2F;p&gt;

&lt;p&gt;
That can be a lot of work if we&#x27;ve got a lot of states, so pf_purge_thread()
breaks that up into smaller chuncks, iterating only part of the state table on
every run. Let&#x27;s look at that code:
&lt;&#x2F;p&gt;

&lt;pre class=&quot;sh_cpp&quot;&gt;
void
pf_purge_thread(void *unused __unused)
{
        VNET_ITERATOR_DECL(vnet_iter);
        u_int idx = 0;

        sx_xlock(&amp;pf_end_lock);
        while (pf_end_threads == 0) {
                sx_sleep(pf_purge_thread, &amp;pf_end_lock, 0, &quot;pftm&quot;, hz &#x2F; 10);

                VNET_LIST_RLOCK();
                VNET_FOREACH(vnet_iter) {
                        CURVNET_SET(vnet_iter);


                        &#x2F;* Wait until V_pf_default_rule is initialized. *&#x2F;
                        if (V_pf_vnet_active == 0) {
                                CURVNET_RESTORE();
                                continue;
                        }

                        &#x2F;*
                         *  Process 1&#x2F;interval fraction of the state
                         * table every run.
                         *&#x2F;
                        idx = pf_purge_expired_states(idx, pf_hashmask &#x2F;
                            (V_pf_default_rule.timeout[PFTM_INTERVAL] * 10));

                        &#x2F;*
                         * Purge other expired types every
                         * PFTM_INTERVAL seconds.
                         *&#x2F;
                        if (idx == 0) {
                                &#x2F;*
                                 * Order is important:
                                 * - states and src nodes reference rules
                                 * - states and rules reference kifs
                                 *&#x2F;
                                pf_purge_expired_fragments();
                                pf_purge_expired_src_nodes();
                                pf_purge_unlinked_rules();
                                pfi_kif_purge();
                        }
                        CURVNET_RESTORE();
                }
                VNET_LIST_RUNLOCK();
        }

        pf_end_threads++;
        sx_xunlock(&amp;pf_end_lock);
        kproc_exit(0);
}
&lt;&#x2F;pre&gt;

&lt;p&gt;
We iterate over all of our virtual pf instances (VNET_FOREACH()), check if
it&#x27;s active (for FreeBSD-EN-17.08, where we&#x27;ve seen this code before) and then
check the expired states with pf_purge_expired_states(). We start at state
&#x27;idx&#x27; and only process a certain number (determined by the PFTM_INTERVAL
setting) states. The pf_purge_expired_states() function returns a new idx
value to tell us how far we got.
&lt;&#x2F;p&gt;

&lt;p&gt;
So, remember when I mentioned the odd V_ prefix? Those are per-vnet variables.
They work a bit like thread-local variables. Each vnet (virtual network stack)
keeps its state separate from the others, and the V_ variables use a pointer
that&#x27;s changed whenever we change the currently active vnet (say with
CURVNET_SET() or CURVNET_RESTORE()). That&#x27;s tracked in the &#x27;curvnet&#x27; variable.

In other words: there are as many V_pf_vnet_active variables as there are
vnets: number of vnet jails plus one (for the host system).
&lt;&#x2F;p&gt;

&lt;p&gt;
Why is that relevant here? Note that idx is not a per-vnet variable, but we
handle multiple pf instances here. We run through all of them in fact. That
means that we end up checking the first X states in the first vnet, then check
the second X states in the second vnet, the third X states in the third and so
on and so on.
&lt;&#x2F;p&gt;

&lt;p&gt;
That of course means that we think we&#x27;ve run through all of the states in a
vnet while we really only checked some of them. So when
pf_purge_unlinked_rules() runs it can end up free()ing rules that actually are
still in use because pf_purge_thread() skipped over the state(s) that
actually used the rule.
&lt;&#x2F;p&gt;

&lt;p&gt;
The problem only happened if we reloaded rules in the host jail, because the
active ruleset is never free()d, even if there are no states pointing to the
rule.
&lt;&#x2F;p&gt;

&lt;p&gt;
That explains the panic, and the fix is actually quite straightforward: idx
needs to be a per-vnet variable, V_pf_purge_idx, and then the problem is gone.
&lt;&#x2F;p&gt;

&lt;p&gt;
As is often the case, the solution to a fairly hard problem turns out to be
really simple.
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>FreeBSD-EN-17:08.pf</title>
  <link>http://www.sigsegv.be/blog/freebsd/FreeBSD-EN-17.08.pf.html</link>
  <description>
&lt;p&gt;
Allan twisted my arm in &lt;a href=&quot;http:&#x2F;&#x2F;www.jupiterbroadcasting.com&#x2F;117861&#x2F;signals-gotta-catch-em-all-bsd-now-209&#x2F;&quot;&gt;BSDNow episode 209&lt;&#x2F;a&gt; so I&#x27;ll have to talk about
&lt;a href=&quot;https:&#x2F;&#x2F;www.freebsd.org&#x2F;security&#x2F;advisories&#x2F;FreeBSD-EN-17:08.pf.asc&quot;&gt;FreeBSD-EN-17:08.pf&lt;&#x2F;a&gt;.
&lt;&#x2F;p&gt;

&lt;p&gt;
First things first, so I have to point out that I think Allan misremembered
things. The heroic debugging story is &lt;a
href=&quot;https:&#x2F;&#x2F;bugs.freebsd.org&#x2F;bugzilla&#x2F;show_bug.cgi?id=219251&quot;&gt;PR 219251&lt;&#x2F;a&gt;,
which I&#x27;ll try to write about later.
&lt;&#x2F;p&gt;

&lt;p&gt;
FreeBSD-EN-17:08.pf is an issue that affected some FreeBSD 11.x systems, where
FreeBSD would panic at startup. There were no reports for CURRENT. That looked
like this:
&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;FreeBSD-EN-17.08.pf.png&quot; alt=&quot;Crash information&quot;&#x2F;&gt;
&lt;&#x2F;p&gt;

&lt;p&gt;
There&#x27;s very little to go on here, but we do now the cause of the panic
(&quot;integer divide fault&quot;), and that the current process was &quot;pf purge&quot;.  The pf
purge thread is part of the pf housekeeping infrastructure. It&#x27;s a housekeeping
kernel thread which cleans up things like old states and expired fragments.
&lt;&#x2F;p&gt;

Here&#x27;s the core loop:

&lt;pre class=&quot;sh_cpp&quot;&gt;
void
pf_purge_thread(void *unused __unused)
{
        VNET_ITERATOR_DECL(vnet_iter);
        u_int idx = 0;

        sx_xlock(&amp;pf_end_lock);
        while (pf_end_threads == 0) {
                sx_sleep(pf_purge_thread, &amp;pf_end_lock, 0, &quot;pftm&quot;, hz &#x2F; 10);

                VNET_LIST_RLOCK();
                VNET_FOREACH(vnet_iter) {
                        CURVNET_SET(vnet_iter);

                        &#x2F;*
                         *  Process 1&#x2F;interval fraction of the state
                         * table every run.
                         *&#x2F;
                        idx = pf_purge_expired_states(idx, pf_hashmask &#x2F;
                            (V_pf_default_rule.timeout[PFTM_INTERVAL] * 10));

                        &#x2F;*
                         * Purge other expired types every
                         * PFTM_INTERVAL seconds.
                         *&#x2F;
                        if (idx == 0) {
                                &#x2F;*
                                 * Order is important:
                                 * - states and src nodes reference rules
                                 * - states and rules reference kifs
                                 *&#x2F;
                                pf_purge_expired_fragments();
                                pf_purge_expired_src_nodes();
                                pf_purge_unlinked_rules();
                                pfi_kif_purge();
                        }
                        CURVNET_RESTORE();
                }
                VNET_LIST_RUNLOCK();
        }

        pf_end_threads++;
        sx_xunlock(&amp;pf_end_lock);
        kproc_exit(0);
}
&lt;&#x2F;pre&gt;

&lt;p&gt;
The lack of mention of pf functions in the backtrace is a hint unto itself. 
It suggests that the error is probably directly in pf_purge_thread(). It might
also be in one of the static functions it calls, because compilers often just
inline those so they don&#x27;t generate stack frames.
&lt;&#x2F;p&gt;

&lt;p&gt;

Remember that the problem is an &quot;integer divide fault&quot;. How can integer
divisions be a problem? Well, you can try to divide by zero. The most obvious
suspect for this is this code:
&lt;&#x2F;p&gt;

&lt;pre class=&quot;sh_cpp&quot;&gt;
	idx = pf_purge_expired_states(idx, pf_hashmask &#x2F;
		(V_pf_default_rule.timeout[PFTM_INTERVAL] * 10));
&lt;&#x2F;pre&gt;

&lt;p&gt;
However, this variable is both correctly initialised (in pfattach_vnet()) and
can only be modified through the DIOCSETTIMEOUT ioctl() call and that one
checks for zero.
&lt;&#x2F;p&gt;

&lt;p&gt;
At that point I had no idea how this could happen, but because the problem did
not affect CURRENT I looked at the commit history and found &lt;a
href=&quot;https:&#x2F;&#x2F;svnweb.freebsd.org&#x2F;changeset&#x2F;base&#x2F;312943&quot;&gt;this commit&lt;&#x2F;a&gt; from
Luiz Otavio O Souza:
&lt;&#x2F;p&gt;

&lt;pre&gt;
	Do not run the pf purge thread while the VNET variables are not
	initialized, this can cause a divide by zero (if the VNET initialization
	takes to long to complete).

	Obtained from:	pfSense
	Sponsored by:	Rubicon Communications, LLC (Netgate)
&lt;&#x2F;pre&gt;

&lt;p&gt;
That sounds very familiar, and indeed, applying the patch fixed the problem.
Luiz explained it well: it&#x27;s possible to use V_pf_default_rule.timeout before
it&#x27;s initialised, which caused this panic.
&lt;&#x2F;p&gt;

&lt;p&gt;
To me, this reaffirms the importance of writing good commit messages: because
Luiz mentioned both the pf purge thread and the division by zero I was easily
able to find the relevant commit. If I hadn&#x27;t found it this fix would have
taken a lot longer.
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>&lt;p&gt;Bug reports&lt;&#x2F;p&gt;</title>
  <link>http://www.sigsegv.be/blog/rant/bug_reports.html</link>
  <description>

&lt;p&gt;
I&#x27;ve noticed that many testers, project&#x2F;program&#x2F;product managers, ... 
have no idea on how to properly report bugs, or request new features.
&lt;&#x2F;p&gt;

&lt;p&gt;
It&#x27;s well known that developers will do everything they can to avoid actually
writing code, so it&#x27;s vitally important to avoid falling for their traps when
reporting a bug. My fellow developers will be angry with me for giving away
this secret information, but, well, it wants to be free!
&lt;&#x2F;p&gt;

&lt;p&gt;
Here are a few hints:
&lt;&#x2F;p&gt;

&lt;p&gt;
&lt;ul&gt;

&lt;li&gt;
  &lt;p&gt;
  If you have multiple products or configurations avoid telling the developer
  which one you&#x27;re talking about. This forces him to verify and fix all of
  them. If you&#x27;re naive enough to specify the product he won&#x27;t fix any of the 
  others if they happen to be affected as well.
  &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;
  &lt;p&gt;
  Sometimes a picture doesn&#x27;t say quite as much as a thousand words.
  There are two schools of thought: the large and the small.
  &lt;&#x2F;p&gt;

  &lt;p&gt;
  The first option is to make sure the screenshot includes &lt;b&gt;everything&lt;&#x2F;b&gt;:
  your complete desktop, your e-mail client, the application, your second
  monitor full of goat pornography and bonzi-buddy, ...
  &lt;&#x2F;p&gt;

  &lt;p&gt;
  Ideally you&#x27;d save this screenshot as an uncompressed bitmap so it&#x27;s
  at least 150MB in size. Don&#x27;t let it be said that you didn&#x27;t provide any
  information. 150MB is a &lt;b&gt;lot&lt;&#x2F;b&gt; of information! &lt;br&#x2F;&gt;
  For bonus points, use a video closeup of the screen. Close enough that you
  can see the individual pixels. Now that&#x27;s a detailed report.
  &lt;&#x2F;p&gt;

  &lt;p&gt;
  The second option is to include only the error message. Preferably focussed
  on the message box with the error message, if possibly cutting off most of
  the error message itself. A true master will only include the exclamation
  mark, skull &amp; bones, or other icon.
  &lt;&#x2F;p&gt;
  &lt;p&gt;
  Focus on the essentials! Compress this screenshot mercilessly. Make sure
  it&#x27;s completely unreadable.
  &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;&lt;p&gt;
  File lots and lots of bugs. If, for example, your application has four modes
  dealing with frobnicks and all four nick before frobbing rather than
  frobbing and then nicking make sure you file four bugs. There&#x27;s no way 
  these problems are related and could be tracked in the same bug.
&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;

&lt;li&gt; &lt;p&gt;
  Make sure to remind the developer that he&#x27;s supposed to fix the problem.
  If you report a crash don&#x27;t forget to tell him that the application is not
  supposed to crash. If you don&#x27;t he&#x27;ll just claim that this is normal, and do
  nothing.
&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;

&lt;li&gt;&lt;p&gt;
  Include as little information as possible in the bug report. Developers are
  like kittens. They have a very short attention span and are easily... &lt;i&gt;ooh!
  A shiny!&lt;&#x2F;i&gt;
&lt;&#x2F;p&gt;&lt;&#x2F;li&gt;

&lt;li&gt;&lt;p&gt;
  If the application spouts a load of incomprehensible gibberish when it crashes
  whatever you do, don&#x27;t include that information in the bug report!
  You don&#x27;t understand what it means, so there&#x27;s no way the developer will
  understand it either. Making him feel stupid isn&#x27;t going to get your problem fixed
  any quicker.&lt;br&#x2F;&gt;
  Besides, he&#x27;s a developer, if he was smart he&#x27;d have a real job.
&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;
  &lt;p&gt;Whatever you do, do not follow up on requests for more information. 
  Asking for more information is a favorite trick of programmers to avoid
  having to work on the problem. Don&#x27;t fall for it, don&#x27;t give him the excuse,
  so just ignore the request completely.&lt;&#x2F;p&gt;
  &lt;p&gt;
  If the programmer is very experienced and lazy he might go as far as
  assigning the bug report back to you. Again, don&#x27;t fall for that, but give
  him hell about being so lazy! Demand to know why he thinks he can assign bugs
  to you! His job is closing bugs, not assigning them! Whatever you do, do not
  give him more information.
  &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;
&lt;p&gt;
  If cornered, as a last resort, you can offer more information, but even then
  you can be crafty: make sure the follow-up information contradicts the
  original report.
&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;
&lt;p&gt;
  Offer as much context as possible: make vague allusions to remarks made by a
  third party, in which no developer was present. You know what you mean, he
  should know too.
&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;

&lt;li&gt;
  &lt;p&gt;
  Whatever you do, don&#x27;t attach logs files to the bug report.  Instead, keep
  them somewhere the developer won&#x27;t find them, so you have some evidence on
  hand to prove that he&#x27;s not helping you.
  &lt;&#x2F;p&gt;

  &lt;p&gt;
  Certainly don&#x27;t attach logs if the bug is hard to reproduce, or only occurs
  rarely. The developer would have to wade though thousands of log lines and
  would never get round to actually fixing the bug!
  &lt;&#x2F;p&gt;
  &lt;p&gt;
  Developers just *love* reading &#x27;Time under test: +&#x2F;- 700hours&#x27; in a bug
  report with basically no other details!
  &lt;&#x2F;p&gt;
  &lt;p&gt;
  Ignore increasingly desperate requests for log files. They&#x27;re just another
  form of the request for more information. As soon as you respond you
  validate the developer&#x27;s excuse for not actually fixing the bug.
  &lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;p&gt;
In conclusion, the ideal bug report is &quot;It breaky. You fix.&quot;.
&lt;&#x2F;p&gt;

&lt;p&gt;
In case someone doesn&#x27;t get it, the above suggestions are &lt;b&gt;NOT&lt;&#x2F;b&gt;
something you should do in bug reports. Unfortunately just about all of these
are based on one or more bug reports I have received over the years.
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>Hotmail</title>
  <link>http://www.sigsegv.be/blog/rant/hotmail.html</link>
  <description>

&lt;p&gt;
No, I don&#x27;t use them, but sometimes I send e-mail to people who do. It turns
out that they don&#x27;t like my e-mail. It sends up in the spam bucket.
&lt;&#x2F;p&gt;
&lt;p&gt;
After finding someone with a little clue who still remembered having a
hotmail address I obtained the headers for one of my mails.
It had this in it:
&lt;&#x2F;p&gt;

&lt;pre&gt;
Authentication-Results: hotmail.com; spf=temperror ...
&lt;&#x2F;pre&gt;

&lt;p&gt;
The &lt;a href=&quot;http:&#x2F;&#x2F;www.openspf.org&#x2F;FAQ&#x2F;Hotmail_and_TempError&quot;&gt;OpenSPF&lt;&#x2F;a&gt;
people explain what this means:
&lt;br&#x2F;&gt;

&lt;i&gt;Hotmail does not use live DNS for Sender ID. They have a DNS cache that they
update twice per day. All TempError means is that your domain&#x27;s SPF record is
not in their cache. To get your record added to their cache, send an e-mail
message to senderid@microsoft.com with your domain in it. They will add it,
but be patient as it&#x27;s a manual process and the cache only updates twice a
day.&lt;&#x2F;i&gt;

&lt;&#x2F;p&gt;

&lt;p&gt;
It appears that Microsoft don&#x27;t even understand DNS (or e-mail). Why does that
still surprise me?
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>AsciiDoc is great, but...</title>
  <link>http://www.sigsegv.be/blog/qinotify.html</link>
  <description>

&lt;p&gt;
I was recently(-ish) introduced to &lt;a href=&quot;http:&#x2F;&#x2F;www.methods.co.nz&#x2F;asciidoc&#x2F;&quot;&gt;AsciiDoc&lt;&#x2F;a&gt; by &lt;a href=&quot;http:&#x2F;&#x2F;blog.lick-me.org&#x2F;&quot;&gt;a rather strange individual&lt;&#x2F;a&gt;.
&lt;&#x2F;p&gt;
&lt;p&gt;
Suffice to say I&#x27;ve pretty much fallen in love with it. It pretty much
mirrors the way I type plain text documentation, but it manages to generate
quite pretty HTML output.
All of the advantages of plain text (I get to use Vim, version control Just
Works, ...), with only one downside: no previews of what I&#x27;m doing.
&lt;&#x2F;p&gt;
&lt;p&gt;
So I did something about that: &lt;a
href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kprovost&#x2F;qinotify&quot;&gt;qinotify&lt;&#x2F;a&gt; is a small Qt utility
which monitors .asciidoc files with for changes, and displays the latest
version of the HTML output.
&lt;&#x2F;p&gt;
&lt;p&gt;
&lt;a href=&quot;&#x2F;files&#x2F;qinotify.jpg&quot;&gt;&lt;img src=&quot;&#x2F;files&#x2F;qinotify_small.jpg&quot;&#x2F;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>Sometime I hate Google</title>
  <link>http://www.sigsegv.be/blog/I_hate_google.html</link>
  <description>

&lt;p&gt;
Sometimes I hate Google, or at least their mail admins. They seem to have
entirely missed the point of &lt;a
href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Sender_Policy_Framework&quot;&gt;SPF records&lt;&#x2F;a&gt;.
&lt;&#x2F;p&gt;

&lt;p&gt;
I publish them, not because I believe they&#x27;ll fix the spam problem, but because
a spammer has taken to forging their sender address to appear to originate from
my domain. Obviously none of my servers are involved in such loathsome activities.&lt;br&#x2F;&gt;
I publish these records to give other mail admins the chance to reject such
e-mail outright, or at least to assign it a higher spam probability but mostly
so they won&#x27;t bug me about having rejected it.
&lt;&#x2F;p&gt;

&lt;p&gt;
Google rather seem to have missed the point though because they use them to
reject the spam, which is good, and &lt;b&gt;then send delivery failures to me&lt;&#x2F;b&gt;.
They &lt;i&gt;know&lt;&#x2F;i&gt; that it&#x27;s spam with a forged sender, that&#x27;s why they&#x27;re
rejecting it in the first place, yet they bug me about it.
&lt;&#x2F;p&gt;

&lt;pre&gt;
Delivery to the following recipient failed permanently:

     efqrbsuglyjfuhxy3uca3w1b@jbinup.com

----- Original message -----

X-Received: by 10.68.42.9 with SMTP id j9mr23765326pbl.142.1362320729989;
        Sun, 03 Mar 2013 06:25:29 -0800 (PST)
Return-Path: &lt;B37FBAB0D@sigsegv.be&gt;
Received: from [41.143.193.146] ([41.143.193.146])
        by mx.google.com with ESMTP id tv4si18179919pbc.155.2013.03.03.06.25.24;
        Sun, 03 Mar 2013 06:25:29 -0800 (PST)
Received-SPF: fail (google.com: domain of B37FBAB0D@sigsegv.be does not designate 41.143.193.146 as permitted   
+sender) client-ip=41.143.193.146;
Authentication-Results: mx.google.com;
       spf=hardfail (google.com: domain of B37FBAB0D@sigsegv.be does not designate 41.143.193.146 as permitted s
+ender) smtp.mail=B37FBAB0D@sigsegv.be
From: &quot;Tanya Guerrero&quot; &lt;B37FBAB0D@sigsegv.be&gt;
Subject: hi there
To: &lt;efqrbsuglyjfuhxy3uca3w1b@jbinup.com&gt;
List-Unsubscribe: &lt;mailto:AECC66917F02905@inbalancesolutions.com&gt;
Content-Transfer-Encoding: 8bit
Content-Type: text&#x2F;plain; chars=&quot;iso-8859-1&quot;
Date: Sun, 03 Mar 2013 14:25:21 -0000
Message-ID: &lt;20130303142521.244356B88AC8AC5DC029.4744484@SARA-PC&gt;

SPAM SPAM SPAM

&lt;&#x2F;pre&gt;


</description>
</item>

<item>
  <title>Open sores</title>
  <link>http://www.sigsegv.be/blog/open_sores.html</link>
  <description>
&lt;p&gt;
  After complaining about Microsoft last time I figured I&#x27;d do something
  different this time: I&#x27;m going to complain about a piece of open source
  software.
&lt;&#x2F;p&gt;
&lt;p&gt;
  It needs no introduction, but I&#x27;ll give it one anyway:
  The ISC DHCP server and client are &lt;b&gt;the&lt;&#x2F;b&gt; standard DHCP(v4&#x2F;v6)
  implementations and they&#x27;re used all over the place.
  &lt;br&#x2F;&gt;
  Recently I was fixing a bug in a dhclient-script.sh. It incorrectly 
  parsed an IAID value because it contained an &#x27;=&#x27;.
&lt;p&gt;
&lt;p&gt;
  The relevant bits of source code:
&lt;pre class=&quot;sh_cpp&quot;&gt;
	ient_envadd(client, prefix, &quot;iaid&quot;, &quot;%s&quot;,
			print_hex_1(4, ia-&gt;iaid, 12));
&lt;&#x2F;pre&gt;
This just adds the IAID value to the environment encoded, you&#x27;d expect, as
a hex string.
&lt;br&#x2F;&gt;
Hang on? Hex string? Didn&#x27;t I just say that we got an &#x27;=&#x27; in the data? 
&lt;&#x2F;p&gt;

&lt;p&gt;
Looking a little deeper there&#x27;s the first disturbing bit:
&lt;pre class=&quot;sh_cpp&quot;&gt;
#define print_hex_1(len, data, limit) print_hex(len, data, limit, 0)
#define print_hex_2(len, data, limit) print_hex(len, data, limit, 1)
#define print_hex_3(len, data, limit) print_hex(len, data, limit, 2)
&lt;&#x2F;pre&gt;
Umm, ok then.
&lt;&#x2F;p&gt;

&lt;p&gt;
&lt;pre class=&quot;sh_cpp&quot;&gt;
#define HBLEN 1024
char *print_hex(len, data, limit, buf_num)
        unsigned len;       
        const u_int8_t *data;
        unsigned limit;      
        unsigned buf_num;    
{
        static char hex_buf_1[HBLEN + 1];
        static char hex_buf_2[HBLEN + 1];
        static char hex_buf_3[HBLEN + 1];
        char *hex_buf;

        switch(buf_num) {
          case 0:
                hex_buf = hex_buf_1;
                if (limit &gt;= sizeof(hex_buf_1))
                        limit = sizeof(hex_buf_1);
                break;
          case 1:
                hex_buf = hex_buf_2;
                if (limit &gt;= sizeof(hex_buf_2)) 
                        limit = sizeof(hex_buf_2);
                break;   
          case 2:        
                hex_buf = hex_buf_3;
                if (limit &gt;= sizeof(hex_buf_3))
                        limit = sizeof(hex_buf_3);
                break;
          default:
                return(NULL);
        }

        print_hex_or_string(len, data, limit, hex_buf);
        return(hex_buf);
}
&lt;&#x2F;pre&gt;
Wait what? What&#x27;s with the three static buffers?
&lt;br&#x2F;&gt;
It&#x27;s an evil, and stupid little trick to avoid having to supply a buffer from the caller. 
That&#x27;s why there&#x27;s a static buffer: the caller can just use the returned pointer 
without having to worry about freeing allocated memory. 
&lt;br&#x2F;&gt;
There&#x27;s three of them because presumably at some point someone tried to convert two strings
before printing them and discovered that only both always had the same content when he used 
the output. Instead of solving the problem properly he decided to use this disgusting hack instead.
&lt;br&#x2F;&gt;
That&#x27;s bad, but what about print_hex_or_string?
&lt;&#x2F;p&gt;

&lt;p&gt;
&lt;pre class=&quot;sh_cpp&quot;&gt;
&#x2F;*      
 * print a string as either text if all the characters
 * are printable or colon separated hex if they aren&#x27;t
 *        
 * len - length of data 
 * data - input data
 * limit - length of buf to use 
 * buf - output buffer
 *&#x2F;       
void print_hex_or_string (len, data, limit, buf)
        unsigned len;
        const u_int8_t *data; 
        unsigned limit;
        char *buf;
{               
        unsigned i;
        if ((buf == NULL) || (limit &lt; 3))
                return;
          
        for (i = 0; (i &lt; (limit - 3)) &amp;&amp; (i &lt; len); i++) {
                if (!isascii(data[i]) || !isprint(data[i])) {
                        print_hex_only(len, data, limit, buf);
                        return;
                }
        }

        buf[0] = &#x27;&quot;&#x27;;
        i = len;
        if (i &gt; (limit - 3))
                i = limit - 3;
        memcpy(&amp;buf[1], data, i);
        buf[i + 1] = &#x27;&quot;&#x27;;
        buf[i + 2] = 0;
        return;
}       
&lt;&#x2F;pre&gt;
Well, that&#x27;s about as bad as the function name sounded. This converts the supplied data
into a string, either by interpreting it as plain ASCII (if all of the bytes are printable), 
or converting it into a real hex string.
&lt;br&#x2F;&gt;

Enjoy yourself parsing that. Writing parsing and validation code is so much fun 
and now you get to do it twice!
&lt;&#x2F;p&gt;


</description>
</item>

<item>
  <title>A brief rant.</title>
  <link>http://www.sigsegv.be/blog/A_brief_rant.html</link>
  <description>
&lt;p&gt;
	Observe the &lt;a href=&quot;http:&#x2F;&#x2F;msdn.microsoft.com&#x2F;en-us&#x2F;library&#x2F;windows&#x2F;hardware&#x2F;ff561606%28v=vs.85%29.aspx&quot;&gt;
	NdisAllocateMemoryWithTagPriority&lt;&#x2F;a&gt;[1] function.
&lt;&#x2F;p&gt;
&lt;pre&gt;
PVOID NdisAllocateMemoryWithTagPriority(
  __in  NDIS_HANDLE NdisHandle,
  __in  UINT Length,
  __in  ULONG Tag,
  __in  EX_POOL_PRIORITY Priority
);
&lt;&#x2F;pre&gt;
&lt;p&gt;
	Read the documentation:
&lt;&#x2F;p&gt;
&lt;pre&gt;
&lt;&#x2F;i&gt;Tag [in]&lt;&#x2F;i&gt;
    A string, delimited by single quotation marks, with up to four characters, usually specified in reversed order. 
    The NDIS-supplied default tag for this call is &#x27;maDN&#x27;, but the caller can override this default by supplying an explicit value.
&lt;&#x2F;pre&gt;
&lt;p&gt;
	That&#x27;s right. Pass that string as a ULONG please. I just don&#x27;t have the words.
&lt;&#x2F;p&gt;
&lt;p&gt;
	[1]Think kmalloc, but harder to type.
&lt;&#x2F;p&gt;

</description>
</item>

<item>
  <title>World IPv6 day</title>
  <link>http://www.sigsegv.be/blog/world_IPv6_day.html</link>
  <description>
&lt;p&gt;
	A little while ago (well, a long while, but I&#x27;ve been busy) the 
	&lt;a href=&quot;http:&#x2F;&#x2F;www.isoc.org&#x2F;&quot;&gt;Internet Society&lt;&#x2F;a&gt; organised 
	&lt;a href=&quot;http:&#x2F;&#x2F;www.worldipv6day.org&#x2F;&quot;&gt;World IPv6 day&lt;&#x2F;a&gt;.
&lt;&#x2F;p&gt;
&lt;p&gt;
	I&#x27;m not going to bother explaining what that was about, I&#x27;m sure everyone knows 
	by now. Instead, I&#x27;m going to complain about a 
	&lt;a href=&quot;http:&#x2F;&#x2F;www.sigsegv.be&#x2F;blog&#x2F;ipv6_planet_grep.1024px&quot;&gt;little experiment&lt;&#x2F;a&gt; 
	I did more than three years ago.
	Hopefully all the buzz around World IPv6 day and the IANA pool exhaustion has encouraged
	a few more people to offer their blog over modern IPv6, in addition to crusty old IPv4.
&lt;&#x2F;p&gt;
&lt;p&gt;
	The results are, ... well, results. Three years ago there was one blog in Planet Grep which 
	was reachable on the IPv6 internet. This blog is still there (though with a different IP)
	and there&#x27;s all of four more. That&#x27;s 5 out of 69, or 7.24%.
	&lt;br&#x2F;&gt;
	Just for fun I reran the test on the current list of blogs on Planet Grep. 7 of 97 
	sites, or 7.21% have an IPv6 address.
	&lt;br&#x2F;&gt;
	Not exactly great that. On the bright side: at least the sites which advertise quad-A records 
	are indeed reachable on those addresses, and the one site which had an IPv6 address
	back in 2008 still has one.
&lt;&#x2F;p&gt;
&lt;p&gt;
	Come on guys (and girls obviously), we can do better than this.
&lt;&#x2F;p&gt;


</description>
</item>

<item>
  <title>Change is a constant</title>
  <link>http://www.sigsegv.be/blog/change_is_constant.html</link>
  <description>
&lt;p&gt;
  Just in case I haven&#x27;t told everyone yet, I&#x27;ll be leaving my current employer mid January.
  From then on I&#x27;ll be freelancing. I&#x27;ve already got a &lt;a href=&quot;http:&#x2F;&#x2F;www.codepro.be&quot;&gt;website&lt;&#x2F;a&gt; 
  and everything. (Well, not everything. In fact, just the website, but the rest is being worked on.)
&lt;&#x2F;p&gt;

&lt;p&gt;
  Why? Well, two reasons really, the first is that a really interesting project and the second
  is the bad influence &lt;a href=&quot;http:&#x2F;&#x2F;www.codematters.be&#x2F;&quot;&gt;of&lt;&#x2F;a&gt; 
  &lt;a href=&quot;http:&#x2F;&#x2F;cobbaut.blogspot.com&#x2F;&quot;&gt;a&lt;&#x2F;a&gt; &lt;a href=&quot;http:&#x2F;&#x2F;www.paeps.cx&quot;&gt;few&lt;a&gt; 
  &lt;a href=&quot;http:&#x2F;&#x2F;jabberwocky.eu&#x2F;&quot;&gt;friends&lt;&#x2F;a&gt;.
&lt;&#x2F;p&gt;

&lt;p&gt;
  If you have a problem, if no one else can help, ...&lt;br&#x2F;&gt;
  Well, you should probably call the &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_A-Team&quot;&gt;A-Team&lt;&#x2F;a&gt;,
  but you&#x27;ve got a software problem you should call me. The A-Team doesn&#x27;t know anything about software.
&lt;&#x2F;p&gt;

</description>
</item>

</channel>
</rss>
