Using the 5.10 kernel source
REFS:
- https://www.kernel.org/doc/html/latest/networking/tipc.html
- http://tipc.sourceforge.net/protocol.html
- https://datatracker.ietf.org/doc/html/draft-maloy-tipc-01.txt#page-77
- https://github.com/wireshark/wireshark/blob/8efad466c4e62b0371659c8fd1d909038c36da27/epan/dissectors/packet-tipc.c#L1022
Looked at this commit, there are changes made to the tipc_link_xmit
function.
When patched, this is printed in dmesg when the POC is run.
tipc: Too large msg, purging xmit list 1 5 0 40 4!
tipc: Too large msg, purging xmit list 1 15 0 60 4!
These correspond to the two messages sent in the POC. Mapping these out to their assignments in the function
# The discovery message
purging xmit list 1 5 0 40 4
skb_queue_len(list) = 1
msg_user(hdr) = 5
msg_type(hdr) = 0
msg_size(hdr) = 40
mtu = 4
# The activate/reset message
purging xmit list 1 15 0 60 4
skb_queue_len(list) = 1
msg_user(hdr) = 15
msg_type(hdr) = 0
msg_size(hdr) = 60
mtu = 4
So the MTU is caught here as 4. But why?
Looking at what was added:
Originally the hdr
was defined as buf_msg(skb_peek(list))
and was redefined to be a new tipc_msg struct called hdr
.
- This is just a 60 byte array that holds the maximum size of a message header. The internal header is 60 bytes, while others are 40.
- This means that the hdr is not blindly cast from the next SKB in the queue.
Now a check is made for pkt_cnt <= 0
which is defined by the size of the queue of unprocessed packets (skb). If there are no more packets left, or if the number is negative, then return 0.
My hunch is now that the DOS happened because it was trying to parse SKBs that were not there. This while loop may have just sent it into an unknown state due to parsing unknown data in memory.
This is just a best guess, kernel tracing needs to be done.
- tipc_l2_rcv_msg - handle incoming TIPC message from an interface
- tipc_rcv - process TIPC packets/messages arriving from off-node
- tipc_node_link_up - handle addition of link. This calls a wrapper too: __tipc_node_link_up
- tipc_link_add_bc_peer - add a peer node to broadcast link and bearer
- tipc_link_build_bc_init_msg - synchronize broadcast link endpoints.
- tipc_link_xmit - Consumes the buffer chain of messages
The MTU being set to a low value is one part of this, but it could be indicative of a bigger issue.
Let's see what calls it and how connections are initialized:
tipc_accept(struct socket *sock, struct socket *new_sock, int flags, bool kern)
accepts new connections.
This function then calls tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg));
. tipc_sk_finish_conn connects the socket to the peer.
This function is acting on a tipc_sock struct. The tipc_sock->max_pkt
member is what is set by calling the tipc_node_get_mtu
function. This function is called with net
, which is the SKB, the peer_node
passed originally from tipc_accept
and the tsk->portid
which a unique TIPC socket port identity.
tipc_node_get_mtu initializes mtu
with MAX_MSG_SIZE which is 66060. A tipc_node is initialized with tipc_node_find(net, addr);
It has some checks to ensure that the node is valid and if it's on the same network or not. If all of these checks are passed, then the bearer_id
gets assigned to tipc_node->active_links
on Line 217.
This assignment bearer_id = n->active_links[sel & 1];
uses the sel
variable which is the tsk->portid
AND'd with 1. This is because active_links
is a 2 element array of ints. If the bearer_id
is valid, then mtu
is finally assigned to n->links[bearer_id].mtu;
which is an unknown value. Finally there is a call to tipc_node_put and the MTU is returned.
- What does MTU look like in this call? Does it get changed in any way after? Can use printk to investigate.
- Does the tipc_node actually point to a real tipc_node?
Need to figure out how the trailer data is processed. The trailer data containing MTU info is not dissected by wireshark. In the packet that crashes the kernel, the data is all 0s. In a proper message, there is data in the 8 byte buffer at the end.
The two bytes at 0x2D seem to affect whether or not this bug is triggered. When 0, the warning appears in a patched kernel. When either byte isn't 0, then the warning doesn't appear.
0000 4f 40 00 38 40 00 00 00 00 00 80 00 01 00 10 02 O@.8@...........
0010 00 00 00 01 21 50 02 02 01 00 10 02 01 00 10 01 ....!P..........
-----
0020 c0 80 00 00 00 01 70 00 00 55 44 50 31 00 00 00 ......p..UDP1...
0030 00 00 00 00 00 00 00 00 ........
Also should debug and set a breakpoint on tipc_link_xmit
and on tipc_node_get_mtu
(or even just printk) and check out the values we are interested in. Is the hdr pointing to TIPC data in tipc_link_xmit
? Where does the tipc_node point to in tipc_node_get_mtu
? What is the value of mtu
?