Commit 85035568 authored by Allan Stephens's avatar Allan Stephens Committed by David S. Miller

[TIPC]: Enhance validation of format on incoming messages

This patch ensures that TIPC properly handles incoming messages
that have incorrect or unexpected formats.  Most significantly,
it now ensures that each sl_buff has at least as much data as
the message header indicates it should, and that the entire
message header is stored contiguously; this prevents TIPC from
accidentally accessing memory that is not part of the sk_buff.
Signed-off-by: default avatarAllan Stephens <allan.stephens@windriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fe13dda2
...@@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, ...@@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
return buf; return buf;
} }
/**
* link_recv_buf_validate - validate basic format of received message
*
* This routine ensures a TIPC message has an acceptable header, and at least
* as much data as the header indicates it should. The routine also ensures
* that the entire message header is stored in the main fragment of the message
* buffer, to simplify future access to message header fields.
*
* Note: Having extra info present in the message header or data areas is OK.
* TIPC will ignore the excess, under the assumption that it is optional info
* introduced by a later release of the protocol.
*/
static int link_recv_buf_validate(struct sk_buff *buf)
{
static u32 min_data_hdr_size[8] = {
SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE,
MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE
};
struct tipc_msg *msg;
u32 tipc_hdr[2];
u32 size;
u32 hdr_size;
u32 min_hdr_size;
if (unlikely(buf->len < MIN_H_SIZE))
return 0;
msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr);
if (msg == NULL)
return 0;
if (unlikely(msg_version(msg) != TIPC_VERSION))
return 0;
size = msg_size(msg);
hdr_size = msg_hdr_sz(msg);
min_hdr_size = msg_isdata(msg) ?
min_data_hdr_size[msg_type(msg)] : INT_H_SIZE;
if (unlikely((hdr_size < min_hdr_size) ||
(size < hdr_size) ||
(buf->len < size) ||
(size - hdr_size > TIPC_MAX_USER_MSG_SIZE)))
return 0;
return pskb_may_pull(buf, hdr_size);
}
void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
{ {
read_lock_bh(&tipc_net_lock); read_lock_bh(&tipc_net_lock);
...@@ -1794,9 +1844,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1794,9 +1844,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
struct link *l_ptr; struct link *l_ptr;
struct sk_buff *crs; struct sk_buff *crs;
struct sk_buff *buf = head; struct sk_buff *buf = head;
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg;
u32 seq_no = msg_seqno(msg); u32 seq_no;
u32 ackd = msg_ack(msg); u32 ackd;
u32 released = 0; u32 released = 0;
int type; int type;
...@@ -1804,12 +1854,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1804,12 +1854,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
TIPC_SKB_CB(buf)->handle = b_ptr; TIPC_SKB_CB(buf)->handle = b_ptr;
head = head->next; head = head->next;
if (unlikely(msg_version(msg) != TIPC_VERSION))
/* Ensure message is well-formed */
if (unlikely(!link_recv_buf_validate(buf)))
goto cont; goto cont;
#if 0
if (msg_user(msg) != LINK_PROTOCOL)
#endif
msg_dbg(msg,"<REC<");
/* Ensure message data is a single contiguous unit */ /* Ensure message data is a single contiguous unit */
...@@ -1817,6 +1866,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1817,6 +1866,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
goto cont; goto cont;
} }
/* Handle arrival of a non-unicast link message */
msg = buf_msg(buf);
if (unlikely(msg_non_seq(msg))) { if (unlikely(msg_non_seq(msg))) {
link_recv_non_seq(buf); link_recv_non_seq(buf);
continue; continue;
...@@ -1826,19 +1879,26 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1826,19 +1879,26 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
(msg_destnode(msg) != tipc_own_addr))) (msg_destnode(msg) != tipc_own_addr)))
goto cont; goto cont;
/* Locate unicast link endpoint that should handle message */
n_ptr = tipc_node_find(msg_prevnode(msg)); n_ptr = tipc_node_find(msg_prevnode(msg));
if (unlikely(!n_ptr)) if (unlikely(!n_ptr))
goto cont; goto cont;
tipc_node_lock(n_ptr); tipc_node_lock(n_ptr);
l_ptr = n_ptr->links[b_ptr->identity]; l_ptr = n_ptr->links[b_ptr->identity];
if (unlikely(!l_ptr)) { if (unlikely(!l_ptr)) {
tipc_node_unlock(n_ptr); tipc_node_unlock(n_ptr);
goto cont; goto cont;
} }
/*
* Release acked messages /* Validate message sequence number info */
*/
seq_no = msg_seqno(msg);
ackd = msg_ack(msg);
/* Release acked messages */
if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) { if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg)); tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
...@@ -1857,6 +1917,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1857,6 +1917,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
l_ptr->first_out = crs; l_ptr->first_out = crs;
l_ptr->out_queue_size -= released; l_ptr->out_queue_size -= released;
} }
/* Try sending any messages link endpoint has pending */
if (unlikely(l_ptr->next_out)) if (unlikely(l_ptr->next_out))
tipc_link_push_queue(l_ptr); tipc_link_push_queue(l_ptr);
if (unlikely(!list_empty(&l_ptr->waiting_ports))) if (unlikely(!list_empty(&l_ptr->waiting_ports)))
...@@ -1866,6 +1929,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) ...@@ -1866,6 +1929,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
} }
/* Now (finally!) process the incoming message */
protocol_check: protocol_check:
if (likely(link_working_working(l_ptr))) { if (likely(link_working_working(l_ptr))) {
if (likely(seq_no == mod(l_ptr->next_in_no))) { if (likely(seq_no == mod(l_ptr->next_in_no))) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment