Magellan Linux

Annotation of /trunk/kernel26-magellan/patches-2.6.16-r10/0129-2.6.16.15-SCTP-deadlock-CVE-2006-2275.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 70 - (hide annotations) (download)
Thu May 11 19:09:22 2006 UTC (18 years ago) by niro
File size: 5187 byte(s)
import

1 niro 70 From: Neil Horman <nhorman@tuxdriver.com>
2     Date: Sat, 6 May 2006 00:02:09 +0000 (-0700)
3     Subject: [PATCH] SCTP: Allow spillover of receive buffer to avoid deadlock. (CVE-2006-2275)
4     X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/stable/linux-2.6.16.y.git;a=commitdiff;h=2e2a2cd09dd7b3fbc99a1879a54090fd6db16f0c
5    
6     [PATCH] SCTP: Allow spillover of receive buffer to avoid deadlock. (CVE-2006-2275)
7    
8     This patch fixes a deadlock situation in the receive path by allowing
9     temporary spillover of the receive buffer.
10    
11     - If the chunk we receive has a tsn that immediately follows the ctsn,
12     accept it even if we run out of receive buffer space and renege data with
13     higher TSNs.
14     - Once we accept one chunk in a packet, accept all the remaining chunks
15     even if we run out of receive buffer space.
16    
17     Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
18     Acked-by: Mark Butler <butlerm@middle.net>
19     Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
20     Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
21     Signed-off-by: David S. Miller <davem@davemloft.net>
22     Signed-off-by: Chris Wright <chrisw@sous-sol.org>
23     ---
24    
25     --- a/include/net/sctp/structs.h
26     +++ b/include/net/sctp/structs.h
27     @@ -702,6 +702,7 @@ struct sctp_chunk {
28     __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
29     __s8 fast_retransmit; /* Is this chunk fast retransmitted? */
30     __u8 tsn_missing_report; /* Data chunk missing counter. */
31     + __u8 data_accepted; /* At least 1 chunk in this packet accepted */
32     };
33    
34     void sctp_chunk_hold(struct sctp_chunk *);
35     --- a/net/sctp/inqueue.c
36     +++ b/net/sctp/inqueue.c
37     @@ -149,6 +149,7 @@ struct sctp_chunk *sctp_inq_pop(struct s
38     /* This is the first chunk in the packet. */
39     chunk->singleton = 1;
40     ch = (sctp_chunkhdr_t *) chunk->skb->data;
41     + chunk->data_accepted = 0;
42     }
43    
44     chunk->chunk_hdr = ch;
45     --- a/net/sctp/sm_statefuns.c
46     +++ b/net/sctp/sm_statefuns.c
47     @@ -5154,7 +5154,9 @@ static int sctp_eat_data(const struct sc
48     int tmp;
49     __u32 tsn;
50     int account_value;
51     + struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
52     struct sock *sk = asoc->base.sk;
53     + int rcvbuf_over = 0;
54    
55     data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
56     skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
57     @@ -5165,10 +5167,16 @@ static int sctp_eat_data(const struct sc
58     /* ASSERT: Now skb->data is really the user data. */
59    
60     /*
61     - * if we are established, and we have used up our receive
62     - * buffer memory, drop the frame
63     + * If we are established, and we have used up our receive buffer
64     + * memory, think about droping the frame.
65     + * Note that we have an opportunity to improve performance here.
66     + * If we accept one chunk from an skbuff, we have to keep all the
67     + * memory of that skbuff around until the chunk is read into user
68     + * space. Therefore, once we accept 1 chunk we may as well accept all
69     + * remaining chunks in the skbuff. The data_accepted flag helps us do
70     + * that.
71     */
72     - if (asoc->state == SCTP_STATE_ESTABLISHED) {
73     + if ((asoc->state == SCTP_STATE_ESTABLISHED) && (!chunk->data_accepted)) {
74     /*
75     * If the receive buffer policy is 1, then each
76     * association can allocate up to sk_rcvbuf bytes
77     @@ -5179,9 +5187,25 @@ static int sctp_eat_data(const struct sc
78     account_value = atomic_read(&asoc->rmem_alloc);
79     else
80     account_value = atomic_read(&sk->sk_rmem_alloc);
81     -
82     - if (account_value > sk->sk_rcvbuf)
83     - return SCTP_IERROR_IGNORE_TSN;
84     + if (account_value > sk->sk_rcvbuf) {
85     + /*
86     + * We need to make forward progress, even when we are
87     + * under memory pressure, so we always allow the
88     + * next tsn after the ctsn ack point to be accepted.
89     + * This lets us avoid deadlocks in which we have to
90     + * drop frames that would otherwise let us drain the
91     + * receive queue.
92     + */
93     + if ((sctp_tsnmap_get_ctsn(map) + 1) != tsn)
94     + return SCTP_IERROR_IGNORE_TSN;
95     +
96     + /*
97     + * We're going to accept the frame but we should renege
98     + * to make space for it. This will send us down that
99     + * path later in this function.
100     + */
101     + rcvbuf_over = 1;
102     + }
103     }
104    
105     /* Process ECN based congestion.
106     @@ -5229,6 +5253,7 @@ static int sctp_eat_data(const struct sc
107     datalen -= sizeof(sctp_data_chunk_t);
108    
109     deliver = SCTP_CMD_CHUNK_ULP;
110     + chunk->data_accepted = 1;
111    
112     /* Think about partial delivery. */
113     if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
114     @@ -5245,7 +5270,8 @@ static int sctp_eat_data(const struct sc
115     * large spill over.
116     */
117     if (!asoc->rwnd || asoc->rwnd_over ||
118     - (datalen > asoc->rwnd + asoc->frag_point)) {
119     + (datalen > asoc->rwnd + asoc->frag_point) ||
120     + rcvbuf_over) {
121    
122     /* If this is the next TSN, consider reneging to make
123     * room. Note: Playing nice with a confused sender. A
124     @@ -5253,8 +5279,8 @@ static int sctp_eat_data(const struct sc
125     * space and in the future we may want to detect and
126     * do more drastic reneging.
127     */
128     - if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
129     - (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
130     + if (sctp_tsnmap_has_gap(map) &&
131     + (sctp_tsnmap_get_ctsn(map) + 1) == tsn) {
132     SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
133     deliver = SCTP_CMD_RENEGE;
134     } else {