Using the 5.10 kernel source
Analysis of the Patch
Looked at this commit, there are changes made to the
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:
hdr was defined as
buf_msg(skb_peek(list)) and was redefined to be a new tipc_msg struct called
- 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.
Tracing what calls tipc_link_xmit
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
Analyzing the MTU assignment
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.
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.
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