<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.espeweb.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.espeweb.net/" rel="alternate" type="text/html" /><updated>2026-08-23T02:23:13+02:00</updated><id>https://blog.espeweb.net/feed.xml</id><title type="html">foobar</title><subtitle>Just another blog site</subtitle><entry><title type="html">Analyzing infinite loops without a debugger</title><link href="https://blog.espeweb.net/2016/10/09/analyzing-infinite-loops-without-a-debugger.html" rel="alternate" type="text/html" title="Analyzing infinite loops without a debugger" /><published>2016-10-09T23:20:32+02:00</published><updated>2016-10-09T23:20:32+02:00</updated><id>https://blog.espeweb.net/2016/10/09/analyzing-infinite-loops-without-a-debugger</id><content type="html" xml:base="https://blog.espeweb.net/2016/10/09/analyzing-infinite-loops-without-a-debugger.html"><![CDATA[<p>I recently run into an issue regarding an embedded system already deployed in
the field for several customers.</p>

<p>Those systems were running a daemon from us which sometimes at some point after
a few hours or days was reported to have stopped doing the task it was expected
to be doing.</p>

<p>A more fine-grained analysis showed that the daemon process was still running,
and it was not a good sign to see that it was taking 100% of the CPU, even in
scenarios in which that daemon should have been doing almost no work at all.</p>

<p>The system reported that all the CPU load from the process was being spent in
userspace, which looked even more strange, because that daemon was expected to
be offloading most of its work to the kernel. That quickly pointed the issue to
be some kind of infinite tight loop in userspace which was calling no system
calls, probably due to some data structure memory corruption which we were
unable to trigger easily during our test phase. A quick check with <code class="language-plaintext highlighter-rouge">strace</code>
showing no syscalls being issued for the thread taking 100% of the CPU confirmed
the suspicion.</p>

<p>We knew which kind of issue we had in front of us, but how to really find out
where the issue was occurring? If we had known how to trigger it, we could have
reproduced it in our test environment in which we have plenty of tools to
analyze what's going on: modifying the binary to print more information, using
a debugger, etc. However, we were so far able to see it only in production
environments, and that meant we needed to find a way to get at least some
minimal information to know where to start looking at the issue. The problem
with the production environment, which is used for customers, is that it
contains no analysis or debugging tools in it which makes it quite difficult to
find where the program is actually stuck.</p>

<p>Luckily for us, the Linux kernel provides us with some information for processes
running which can be really useful for us in this scenario. I am talking about
<code class="language-plaintext highlighter-rouge">/proc/$PID/task/$TID/stat</code> file here. This file contains information related to
a specific thread <code class="language-plaintext highlighter-rouge">$TID</code> which is part of process <code class="language-plaintext highlighter-rouge">$PID</code>. You can find more
information on the kind of information this file provides by looking at function
<a href="http://lxr.free-electrons.com/source/fs/proc/array.c?v=4.8#L573"><code class="language-plaintext highlighter-rouge">fs/proc/array.c:proc_tid_stat</code></a>
in the kernel. More specifically, we are interested in the 30th value appearing
in that file, which provides us with the <code class="language-plaintext highlighter-rouge">EIP</code> value of the thread specified
from the path of the file. The
<a href="https://en.wikipedia.org/wiki/Program_counter"><code class="language-plaintext highlighter-rouge">EIP</code></a> contains the address of
memory being executed by the thread, which means that in general if we print
that value from time to time we should be able to follow which of our source
code the process is executing, provided of course that we are able to transform
those in-memory process addresses to source code filename &amp; line references.</p>

<p>And of course, we can do that too, and the best gain from this process is that
we don't need to install specific tools into the production system. We can
usually do all the conversion from our PC just taking some small information
from the running system for late post-processing. We basically need two things
from the running production system:</p>

<ul>
  <li>List of <code class="language-plaintext highlighter-rouge">EIP</code> values from the offending thread, obtained as already explained
above.</li>
  <li>Content of the file <code class="language-plaintext highlighter-rouge">proc/$PID/maps</code> from the same process of the offending
thread. We will explain later why is this content sometimes needed.</li>
</ul>

<p>In our system, we will mainly need:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">addr2line</code> tool (part of
<a href="https://www.gnu.org/software/binutils/"><code class="language-plaintext highlighter-rouge">binutils</code></a>)</li>
  <li>binary file of the offending process compiled with debug symbols (compiled
with <code class="language-plaintext highlighter-rouge">-g</code> flags).</li>
</ul>

<p>Now, what's the process involved to convert the running in-memory address into
some file:line information I can use to look at corresponding code? In general,
it's really easy, just call <code class="language-plaintext highlighter-rouge">addr2line</code> like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>addr2line -a -p -C -f -i -e &amp;amp;quot;$EXEFILE&amp;amp;quot; $a
</code></pre></div></div>

<p>For instance, let's say our offending process comes from a binary called
<code class="language-plaintext highlighter-rouge">infinite</code> and we found it's been running at some point at address <code class="language-plaintext highlighter-rouge">400597</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ addr2line -a -p -C -f -i -e infinite 400597
0x0000000000400597: infinite_function at infinite.c:19 (discriminator 1)
</code></pre></div></div>

<p>Cool! we now know the infinite loop scope includes <code class="language-plaintext highlighter-rouge">infinite.c</code> line <code class="language-plaintext highlighter-rouge">19</code>. We
can just pass a few more addresses to have a better idea on which is the code
being called the most.</p>

<p>And now you may be wondering... why the hell do I need that
<code class="language-plaintext highlighter-rouge">/proc/$PID/maps</code>file?! Well... because unfortunately this is not as easy as
shown here for all scenarios. This simple scenario only covers the case in which
the process is running code from the main binary. However, if the process is
running some code inside some shared library at the time we record the <code class="language-plaintext highlighter-rouge">EIP</code>
value, a bit more work must be done.</p>

<p>First of all, we need to generally find out to which module that process'
in-memory code address belongs too. That's the kind of information that <code class="language-plaintext highlighter-rouge">maps</code>
file provides. Let's have a look at an example with the <code class="language-plaintext highlighter-rouge">infinite</code> binary being
run:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat /proc/$(pidof infinite)/maps
00400000-00401000 r-xp 00000000 08:03 3546387                            /infinite
00600000-00601000 r--p 00000000 08:03 3546387                            /infinite
00601000-00602000 rw-p 00001000 08:03 3546387                            /infinite
020ff000-02120000 rw-p 00000000 00:00 0                                  [heap]
7f334b793000-7f334b928000 r-xp 00000000 08:03 658652                     /usr/lib/libc-2.24.so
7f334b928000-7f334bb27000 ---p 00195000 08:03 658652                     /usr/lib/libc-2.24.so
7f334bb27000-7f334bb2b000 r--p 00194000 08:03 658652                     /usr/lib/libc-2.24.so
7f334bb2b000-7f334bb2d000 rw-p 00198000 08:03 658652                     /usr/lib/libc-2.24.so
7f334bb2d000-7f334bb31000 rw-p 00000000 00:00 0
7f334bb31000-7f334bb54000 r-xp 00000000 08:03 658651                     /usr/lib/ld-2.24.so
7f334bd1b000-7f334bd1d000 rw-p 00000000 00:00 0
7f334bd53000-7f334bd54000 r--p 00022000 08:03 658651                     /usr/lib/ld-2.24.so
7f334bd54000-7f334bd55000 rw-p 00023000 08:03 658651                     /usr/lib/ld-2.24.so
7f334bd55000-7f334bd56000 rw-p 00000000 00:00 0
7ffc57345000-7ffc57366000 rw-p 00000000 00:00 0                          [stack]
7ffc573c5000-7ffc573c7000 r--p 00000000 00:00 0                          [vvar]
7ffc573c7000-7ffc573c9000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
</code></pre></div></div>

<p>Let's now imagine we record an address <code class="language-plaintext highlighter-rouge">7f334b84afe0</code>. The <code class="language-plaintext highlighter-rouge">maps</code> shows that
code section of <code class="language-plaintext highlighter-rouge">libc-2.24.so</code> (code section can be identified because it
contains the <code class="language-plaintext highlighter-rouge">x</code> executable flag) is mapped to the process address space at
addresses starting from <code class="language-plaintext highlighter-rouge">7f334b793000</code> going up to <code class="language-plaintext highlighter-rouge">7f334b928000</code>. As our
recorded address falls between those 2 values, it means it's inside the code
section of libc.</p>

<p>Once we know that code comes from libc and not from our main binary, we know we
need to inspect that binary file instead of the one from the main binary when
using <code class="language-plaintext highlighter-rouge">addr2line</code> or other tools like <code class="language-plaintext highlighter-rouge">objdump</code> or <code class="language-plaintext highlighter-rouge">nm</code>.</p>

<p>When using those tools, then we need to remember we should usually use the
offset from the starting point of that module rather than using the memory
address we recorded from our production system. That means, for instance using
last example, that instead of <code class="language-plaintext highlighter-rouge">0x7f334b84afe0</code> we may want to look at offset
<code class="language-plaintext highlighter-rouge">0xB7FE0</code> inside that module (<code class="language-plaintext highlighter-rouge">0x7f334b84afe0</code> - <code class="language-plaintext highlighter-rouge">0x7f334b793000</code>). Let's see
the difference in this scenario:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ addr2line -a -p -C -f -i -e ./infinite 7f334b84afe0
0x00007f334b84afe0: ?? ??:0

$ addr2line -a -p -C -f -i -e /usr/lib/libc-2.24.so 7f334b84afe0
0x00007f334b84afe0: ?? ??:0

$  addr2line -a -p -C -f -i -e /usr/lib/libc-2.24.so B7FE0
0x00000000000b7fe0: __nanosleep_nocancel at :?
</code></pre></div></div>

<p>We can see the last one using the offset starting from the libc code section
works correctly, as we were actually calling <code class="language-plaintext highlighter-rouge">usleep()</code> in the code. There is no
source information (<code class="language-plaintext highlighter-rouge">:?</code> is displayed instead of filename &amp; line) because the
libc I used for the experiment does not contain debug information (hence we see
here too that having the binary in your PC compiled with the <code class="language-plaintext highlighter-rouge">-g</code> is important
to get all the information).</p>

<p>You can find a testbed environment to play with what is discussed here in the
following repository I built up: <a href="https://github.com/pespin/trace-eip">https://github.com/pespin/trace-eip</a></p>]]></content><author><name>{&quot;login&quot; =&gt; &quot;pespin&quot;, &quot;email&quot; =&gt; &quot;pespin.shar@gmail.com&quot;, &quot;display_name&quot; =&gt; &quot;pespin&quot;, &quot;first_name&quot; =&gt; &quot;Pau&quot;, &quot;last_name&quot; =&gt; &quot;Espin Pedrol&quot;}</name><email>pespin.shar@gmail.com</email></author><summary type="html"><![CDATA[I recently run into an issue regarding an embedded system already deployed in the field for several customers.]]></summary></entry><entry><title type="html">iptables TCPMSS target limitation</title><link href="https://blog.espeweb.net/2016/07/18/iptables-tcpmss-target-limitation.html" rel="alternate" type="text/html" title="iptables TCPMSS target limitation" /><published>2016-07-18T18:55:14+02:00</published><updated>2016-07-18T18:55:14+02:00</updated><id>https://blog.espeweb.net/2016/07/18/iptables-tcpmss-target-limitation</id><content type="html" xml:base="https://blog.espeweb.net/2016/07/18/iptables-tcpmss-target-limitation.html"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>I was recently making some tests regarding the behavior of a given transparent
TCP proxy where IPv6 is in use. Specifically, I wanted to test the scenario in
which some network link in the destination path after the proxy contained an
unusually small MTU.</p>

<h2 id="state-of-the-art">State of the art</h2>

<p>First of all, let's remember that IPv6 doesn't support
<a href="https://en.wikipedia.org/wiki/IPv6_packet#Fragmentation">fragmentation</a> inside
middle-boxes, but it is explicitly stated that fragmentation should be done by
the endpoints. Usually that means that endpoints should have some kind of PMTU
Discovery algorithm to try to guess the best MSS which can fill the MTU as much
as possible without exceeding its maximum size.</p>

<p>In case of TCP, an MSS option is available (see
<a href="https://tools.ietf.org/html/rfc6691">rfc6691</a>) to tell your peer at connection
establishment time (<em>SYN</em>, <em>SYN/ACK</em>) which is the maximum MSS you expect to
receive according to your knowledge of the network surrounding you. This way,
your peer knows how much data can he store in every packet in order to be able
to avoid it being dropped by some router in the way. Then, ideally, smart
middle-boxes routing this kind of packets should modify its TCP MSS option
value, lowering it in case the next hop is known to contain a smaller MTU.
Following this procedure, when the packet reaches the other endpoint, the MSS
value is correctly set to match the value needed for the lowest MTU on the path.</p>

<p>Sounds good, right? This kinda works... until a dumb middle-box appears in the
path! Let's imagine a router with an output interface whose link is the minimal
one supported by IPv6, that is 1280 bytes. And the SYN packet passes with a nice
<em>MSS=1440</em> option set in it, which of course our dumb friend is not going to
update. Then, the other peer is going to receive this erroneous big value and it
is going to use it, sending packets which are going to exceed the 1280 bytes,
and they will be dropped by the router as there is no fragmentation in IPv6.
Conclusion: TCP MSS option is easy and efficient, but doesn't work in all
scenarios.</p>

<p>Fortunately for us, IPv6 provides its own mechanisms to notify the sender
endpoint that packets too big are being sent. Quickly explained, when a
middle-box drops a packet too big to be forwarded over the MTU of the router
link, it also sends an ICMPv6 "Packet too big" message to the sender (see
<a href="https://tools.ietf.org/html/rfc4443#section-3.2">rfc4443</a>), providing
information on the size needed. This way, the TCP stack of the sender can learn
about the new MSS size required and re-send the information using smaller
packets. As you can see, this procedure would take a long time if it had to be
done for each new hop, that's why TCP MSS option is usually there to help us,
avoiding lots of possible extra round-trip times until first data packet reaches
the receiver.</p>

<h2 id="adding-the-proxy">Adding the proxy</h2>

<p>Let's imagine we are using a simple proxy which creates 2 sockets for each
connection created by a client. The first socket is used to read what the client
sends, and then a second socket is created to communicate server-side. Then, the
proxy basically copies data from one socket to the other, reading/modifying
payload to achieve some kind of objective (we are using a proxy for some reason,
right?). It can be seen that the proxy actually cuts the connection in two,
buffering both end. That is, whatever data is sent from the client is ACKed by
the proxy, and at some point later on, it is sent to the server.</p>

<p>Now, let's imagine the problematic network we talked about before: a network
path to the server with a small MTU and an incorrectly updated MSS TCP option
size, and the client sending some data to the server. As we discussed, we will
receive an ICMPv6 "Packet too big" packet from some middle-box, so...
where's the problem? well, there's a problem. We cannot actually forward back
the ICMPv6 packet, because we are "transparent", and well... we already ACKed
that piece of data when we read it from our client-side socket before sending it
over the server-side socket, which means the client probably doesn't have the
data saved anymore and it won't be able to re-send it (after all, from client
point of view, it supposedly reached the destination, didn't it?).</p>

<p>OK, we cannot forward back the issue to the client and we have a packet too big
to be routed forward.… the best solution so far is to stop forwarding the
icmpv6 "Packet too big" packet and redirect it to our server-side socket, to
let the TCP stack lower the MSS to fit into the offending MTU size. That means,
of course, that we are going to be the ones issuing the fragmentation on behalf
of the client. This is far from optimal, but fortunately it will only be needed
for some specific network paths for which MSS option is not calculated
correctly.</p>

<h2 id="testing">Testing</h2>

<p>As I was explaining a long time ago, at the start of the post, I wanted to see
if the proxy is behaving correctly in this kind of scenarios.</p>

<p>I have a setup with different hosts set-up in line with of course the Proxy in
place. Then, I needed to have somehow this faulty network environment to test it
(aka MSS received by the client being bigger than the real MTU being used).</p>

<h3 id="tcpmss-iptables-target">TCPMSS iptables target</h3>

<p>This was my first idea, which actually didn't work due to a limitation in
TCPMSS iptables target (the original reason to write this post). The setup
consists mainly on two parts:</p>

<ul>
  <li>Set the MTU in the server to 1280 bytes, the minimum one supported by IPv6:
<code class="language-plaintext highlighter-rouge">ip link set dev eth0 mtu 1280</code></li>
  <li>Modify the outgoing <em>SYN/ACK</em> packet which is initially set to some valid
value under 1280 bytes to a bigger invalid value that will force packet drop
and ICMPv6 message generation, let's say 1440: <code class="language-plaintext highlighter-rouge">ip6tables -t mangle -A
POSTROUTING -p tcp --tcp-flags SYN,ACK SYN,ACK -o eth0 -j TCPMSS --set-mss
1440</code></li>
</ul>

<p>Result: Using wireshark, I see the MSS option value in the <em>SYN/ACK</em> packet is
left untouched, with its original value. On the other hand, <code class="language-plaintext highlighter-rouge">ip6tables -L -v -n
-t mangle</code> shows one packet hit the rule... what's going on in here?</p>

<p>From my experience, the best to do in this cases is reading the netfilter kernel
module implementing the iptables target. It is usually quite fast, just check
which kernel config is needed to enable the feature, then see which file it adds
to the build and go see that specific file.</p>

<p>Quick grep in the kernel shows the required information on the location
(<em>net/netfilter/xt_TCPMSS.c</em>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ grep -r TCPMSS
...
net/netfilter/Makefile:obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
...
</code></pre></div></div>

<p>Then, in that file, you can find the following snippet of code:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/* Never increase MSS, even when setting it, as
 * doing so results in problems for hosts that rely
 * on MSS being set correctly.
 */
if (oldmss &gt;= newmss)
    return 0;
</code></pre></div></div>

<p>So, basically checks in the code are actually preventing me to do exactly what I
want to do. I cannot change the MSS to a bigger value than the original one.
This is done to prevent probable malfunctioning or at least sub-optimal use of
the network, but that's exactly the faulty scenario I want to test the proxy
against!</p>

<h3 id="easier-solution">Easier solution</h3>

<p>This one works, and is simpler than the first one, and on top of that, no TCPMSS
iptables rule is needed:</p>

<ul>
  <li>Just set the <em>MTU=1280</em> in interface of middle-box connected to the server,
instead of lowering the MTU in the server itself. This way, the server will
still think the MTU is 1500 (ethernet default) and the MSS calculated on the
<em>SYN/ACK</em> will be based on that instead of 1280. On top of that, the
middle-box is not going to change the MSS option by default unless you
configure it to do so with an iptables rule (you would probably use TCPMSS
module for that!). Then, when a data packet reaches this middle-box and it
tries to forward it to the server using the lowered MTU interface, it will
drop the packet and it will send the ICMPv6 message back to the client (and
will be actually catched by the proxy).</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>TCPMSS iptables module seems to currently have an undocumented limitation, that
is, you cannot increase the existing original MSS value, only decreasing is
allowed.</p>

<p>To add into my TODO list: It may be interesting to add an <code class="language-plaintext highlighter-rouge">--allow-increase</code>
option to iptables TCPMSS module, which should be disabled by default. However,
this would still be a useful-to-have feature for testing (or any scenario which
requires it, for instance handling packets from an incredibly broken middle-box
or TCP stack).</p>]]></content><author><name>{&quot;login&quot; =&gt; &quot;pespin&quot;, &quot;email&quot; =&gt; &quot;pespin.shar@gmail.com&quot;, &quot;display_name&quot; =&gt; &quot;pespin&quot;, &quot;first_name&quot; =&gt; &quot;Pau&quot;, &quot;last_name&quot; =&gt; &quot;Espin Pedrol&quot;}</name><email>pespin.shar@gmail.com</email></author><summary type="html"><![CDATA[Introduction]]></summary></entry></feed>