Thread (1 message) 1 message, 1 author, 2012-04-14

Re: [RFC] endianness bugs in net/batman-adv/

From: Antonio Quartulli <hidden>
Date: 2012-04-14 09:34:05
Also in: batman

On Fri, Apr 13, 2012 at 08:46:29 +0100, Al Viro wrote:
	Let's start with net/batman-adv/translation-table.c:send_tt_request(). 
Its tt_crc argument gets stored into skb as-is and skb goes on the wire.
OK, so it's fixed-endian, right?
ok, it's a bug. The tt_crc field must be stored in the skb by using htons().
	That sucker comes straight from the (only) caller - tt_update_orig().
There it gets compared with ->tt_crc of struct orig_node instances.  Fine,
except that just prior to that comparison we assign to ->tt_crc the return
value of tt_global_crc().  Which is built on crc16_byte() and clearly
returns a host-endian value.  Additionally, orig_node ->tt_crc is getting
compared to tt_request->tt_data in send_other_tt_response(), which ultimately
comes from recv_tt_query() where it's flipped from net-endian to host-endian.
We want to do every computation using host-endian data. There is no "fixed
endian" anywhere. As I wrote above, we forgot to use htons() before sending the
tt_crc over the wire.
	It gets even funnier - we have 3 structures with ->tt_crc in them;
one is struct orig_node (see above), another is struct batman_ogv_packet and
then there's the weirdest one - struct bat_priv.  Where ->tt_crc is
atomic_t, of all things.  With exactly two things ever done to it:
        batman_ogm_packet->tt_crc = htons((uint16_t)
                                                atomic_read(&bat_priv->tt_crc));
in bat_iv_ogm_schedule() and
        atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
in prepare_packet_buffer().  What the hell does that have to do with atomic_t?
Thank you for spotting this. It was defined as atomic_t in the early development
phase of this new tt framework, but, then, I'd say that we forgot to convert it
to uint16_t once atomic_t was not needed anymore.
At least that one is definitely host-endian all along (tt_local_crc() is
the same kind of built-on-crc16_byte() thing).

	And then there's batman_ogv_packet, where we flip the damn field
from net-endian to host-endian and back.  That's where the argument of
tt_update_orig() comes from, AFAICS always in host-endian form.

	IOW, unless I'm misreading that code we have
bat_priv ->tt_crc: host-endian, no need to make it atomic_t
I agree.
orig_node ->tt_crc: host-endian
I agree. As I said before we want to use host-endian everywhere. We just want to
convert the data to net-endian before sending it over the wire (like people
should normally do).
tt_update_orig()/send_tt_request() tt_crc argument: host-endian
I agree.
the value put into the packet in send_tt_request(): broken; should be
net-endian, in reality it's host-endian.  Missing htons() at the very
least.
Exactly. This is the bug I was talking about in my first inline response.

All the problems come from a missing htons() before sending the tt_request
packet.

Thank you very much. I'll fix it.


Best regards,


-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help