Skip to content

Commit

Permalink
[TIPC]: Enhance validation of format on incoming messages
Browse files Browse the repository at this point in the history
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: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Allan Stephens authored and David S. Miller committed Apr 16, 2008
1 parent fe13dda commit 8503556
Showing 1 changed file with 77 additions and 12 deletions.
89 changes: 77 additions & 12 deletions net/tipc/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
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)
{
read_lock_bh(&tipc_net_lock);
Expand All @@ -1794,29 +1844,32 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
struct link *l_ptr;
struct sk_buff *crs;
struct sk_buff *buf = head;
struct tipc_msg *msg = buf_msg(buf);
u32 seq_no = msg_seqno(msg);
u32 ackd = msg_ack(msg);
struct tipc_msg *msg;
u32 seq_no;
u32 ackd;
u32 released = 0;
int type;

b_ptr = (struct bearer *)tb_ptr;
TIPC_SKB_CB(buf)->handle = b_ptr;

head = head->next;
if (unlikely(msg_version(msg) != TIPC_VERSION))

/* Ensure message is well-formed */

if (unlikely(!link_recv_buf_validate(buf)))
goto cont;
#if 0
if (msg_user(msg) != LINK_PROTOCOL)
#endif
msg_dbg(msg,"<REC<");

/* Ensure message data is a single contiguous unit */

if (unlikely(buf_linearize(buf))) {
goto cont;
}

/* Handle arrival of a non-unicast link message */

msg = buf_msg(buf);

if (unlikely(msg_non_seq(msg))) {
link_recv_non_seq(buf);
continue;
Expand All @@ -1826,19 +1879,26 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
(msg_destnode(msg) != tipc_own_addr)))
goto cont;

/* Locate unicast link endpoint that should handle message */

n_ptr = tipc_node_find(msg_prevnode(msg));
if (unlikely(!n_ptr))
goto cont;

tipc_node_lock(n_ptr);

l_ptr = n_ptr->links[b_ptr->identity];
if (unlikely(!l_ptr)) {
tipc_node_unlock(n_ptr);
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 (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
Expand All @@ -1857,6 +1917,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
l_ptr->first_out = crs;
l_ptr->out_queue_size -= released;
}

/* Try sending any messages link endpoint has pending */

if (unlikely(l_ptr->next_out))
tipc_link_push_queue(l_ptr);
if (unlikely(!list_empty(&l_ptr->waiting_ports)))
Expand All @@ -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);
}

/* Now (finally!) process the incoming message */

protocol_check:
if (likely(link_working_working(l_ptr))) {
if (likely(seq_no == mod(l_ptr->next_in_no))) {
Expand Down

0 comments on commit 8503556

Please sign in to comment.