diff options
author | Allan Stephens <allan.stephens@windriver.com> | 2008-04-15 22:04:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-04-15 22:04:54 -0400 |
commit | 85035568a96065de6fb29478707a3ad5f1fed169 (patch) | |
tree | 1f90673d173b40ca48de6eb7d3d65a3d3e64ea46 /net/tipc/link.c | |
parent | fe13dda2d24eca2ee8a6bb8a0af88ab84d589fd6 (diff) |
[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: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 89 |
1 files changed, 77 insertions, 12 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 087379366d3c..2a26a16e269f 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, | |||
1785 | return buf; | 1785 | return buf; |
1786 | } | 1786 | } |
1787 | 1787 | ||
1788 | /** | ||
1789 | * link_recv_buf_validate - validate basic format of received message | ||
1790 | * | ||
1791 | * This routine ensures a TIPC message has an acceptable header, and at least | ||
1792 | * as much data as the header indicates it should. The routine also ensures | ||
1793 | * that the entire message header is stored in the main fragment of the message | ||
1794 | * buffer, to simplify future access to message header fields. | ||
1795 | * | ||
1796 | * Note: Having extra info present in the message header or data areas is OK. | ||
1797 | * TIPC will ignore the excess, under the assumption that it is optional info | ||
1798 | * introduced by a later release of the protocol. | ||
1799 | */ | ||
1800 | |||
1801 | static int link_recv_buf_validate(struct sk_buff *buf) | ||
1802 | { | ||
1803 | static u32 min_data_hdr_size[8] = { | ||
1804 | SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE, | ||
1805 | MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE | ||
1806 | }; | ||
1807 | |||
1808 | struct tipc_msg *msg; | ||
1809 | u32 tipc_hdr[2]; | ||
1810 | u32 size; | ||
1811 | u32 hdr_size; | ||
1812 | u32 min_hdr_size; | ||
1813 | |||
1814 | if (unlikely(buf->len < MIN_H_SIZE)) | ||
1815 | return 0; | ||
1816 | |||
1817 | msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr); | ||
1818 | if (msg == NULL) | ||
1819 | return 0; | ||
1820 | |||
1821 | if (unlikely(msg_version(msg) != TIPC_VERSION)) | ||
1822 | return 0; | ||
1823 | |||
1824 | size = msg_size(msg); | ||
1825 | hdr_size = msg_hdr_sz(msg); | ||
1826 | min_hdr_size = msg_isdata(msg) ? | ||
1827 | min_data_hdr_size[msg_type(msg)] : INT_H_SIZE; | ||
1828 | |||
1829 | if (unlikely((hdr_size < min_hdr_size) || | ||
1830 | (size < hdr_size) || | ||
1831 | (buf->len < size) || | ||
1832 | (size - hdr_size > TIPC_MAX_USER_MSG_SIZE))) | ||
1833 | return 0; | ||
1834 | |||
1835 | return pskb_may_pull(buf, hdr_size); | ||
1836 | } | ||
1837 | |||
1788 | void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | 1838 | void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) |
1789 | { | 1839 | { |
1790 | read_lock_bh(&tipc_net_lock); | 1840 | read_lock_bh(&tipc_net_lock); |
@@ -1794,9 +1844,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | |||
1794 | struct link *l_ptr; | 1844 | struct link *l_ptr; |
1795 | struct sk_buff *crs; | 1845 | struct sk_buff *crs; |
1796 | struct sk_buff *buf = head; | 1846 | struct sk_buff *buf = head; |
1797 | struct tipc_msg *msg = buf_msg(buf); | 1847 | struct tipc_msg *msg; |
1798 | u32 seq_no = msg_seqno(msg); | 1848 | u32 seq_no; |
1799 | u32 ackd = msg_ack(msg); | 1849 | u32 ackd; |
1800 | u32 released = 0; | 1850 | u32 released = 0; |
1801 | int type; | 1851 | int type; |
1802 | 1852 | ||
@@ -1804,12 +1854,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | |||
1804 | TIPC_SKB_CB(buf)->handle = b_ptr; | 1854 | TIPC_SKB_CB(buf)->handle = b_ptr; |
1805 | 1855 | ||
1806 | head = head->next; | 1856 | head = head->next; |
1807 | if (unlikely(msg_version(msg) != TIPC_VERSION)) | 1857 | |
1858 | /* Ensure message is well-formed */ | ||
1859 | |||
1860 | if (unlikely(!link_recv_buf_validate(buf))) | ||
1808 | goto cont; | 1861 | goto cont; |
1809 | #if 0 | ||
1810 | if (msg_user(msg) != LINK_PROTOCOL) | ||
1811 | #endif | ||
1812 | msg_dbg(msg,"<REC<"); | ||
1813 | 1862 | ||
1814 | /* Ensure message data is a single contiguous unit */ | 1863 | /* Ensure message data is a single contiguous unit */ |
1815 | 1864 | ||
@@ -1817,6 +1866,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | |||
1817 | goto cont; | 1866 | goto cont; |
1818 | } | 1867 | } |
1819 | 1868 | ||
1869 | /* Handle arrival of a non-unicast link message */ | ||
1870 | |||
1871 | msg = buf_msg(buf); | ||
1872 | |||
1820 | if (unlikely(msg_non_seq(msg))) { | 1873 | if (unlikely(msg_non_seq(msg))) { |
1821 | link_recv_non_seq(buf); | 1874 | link_recv_non_seq(buf); |
1822 | continue; | 1875 | continue; |
@@ -1826,19 +1879,26 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | |||
1826 | (msg_destnode(msg) != tipc_own_addr))) | 1879 | (msg_destnode(msg) != tipc_own_addr))) |
1827 | goto cont; | 1880 | goto cont; |
1828 | 1881 | ||
1882 | /* Locate unicast link endpoint that should handle message */ | ||
1883 | |||
1829 | n_ptr = tipc_node_find(msg_prevnode(msg)); | 1884 | n_ptr = tipc_node_find(msg_prevnode(msg)); |
1830 | if (unlikely(!n_ptr)) | 1885 | if (unlikely(!n_ptr)) |
1831 | goto cont; | 1886 | goto cont; |
1832 | |||
1833 | tipc_node_lock(n_ptr); | 1887 | tipc_node_lock(n_ptr); |
1888 | |||
1834 | l_ptr = n_ptr->links[b_ptr->identity]; | 1889 | l_ptr = n_ptr->links[b_ptr->identity]; |
1835 | if (unlikely(!l_ptr)) { | 1890 | if (unlikely(!l_ptr)) { |
1836 | tipc_node_unlock(n_ptr); | 1891 | tipc_node_unlock(n_ptr); |
1837 | goto cont; | 1892 | goto cont; |
1838 | } | 1893 | } |
1839 | /* | 1894 | |
1840 | * Release acked messages | 1895 | /* Validate message sequence number info */ |
1841 | */ | 1896 | |
1897 | seq_no = msg_seqno(msg); | ||
1898 | ackd = msg_ack(msg); | ||
1899 | |||
1900 | /* Release acked messages */ | ||
1901 | |||
1842 | if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) { | 1902 | if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) { |
1843 | if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) | 1903 | if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) |
1844 | tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg)); | 1904 | 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 | l_ptr->first_out = crs; | 1917 | l_ptr->first_out = crs; |
1858 | l_ptr->out_queue_size -= released; | 1918 | l_ptr->out_queue_size -= released; |
1859 | } | 1919 | } |
1920 | |||
1921 | /* Try sending any messages link endpoint has pending */ | ||
1922 | |||
1860 | if (unlikely(l_ptr->next_out)) | 1923 | if (unlikely(l_ptr->next_out)) |
1861 | tipc_link_push_queue(l_ptr); | 1924 | tipc_link_push_queue(l_ptr); |
1862 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) | 1925 | 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 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); | 1929 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); |
1867 | } | 1930 | } |
1868 | 1931 | ||
1932 | /* Now (finally!) process the incoming message */ | ||
1933 | |||
1869 | protocol_check: | 1934 | protocol_check: |
1870 | if (likely(link_working_working(l_ptr))) { | 1935 | if (likely(link_working_working(l_ptr))) { |
1871 | if (likely(seq_no == mod(l_ptr->next_in_no))) { | 1936 | if (likely(seq_no == mod(l_ptr->next_in_no))) { |