]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
36a78a2698d3e7ddb39f0f36cdc657a9ddfe6c14
[thirdparty/kernel/stable-queue.git] /
1 From 5fa782c2f5ef6c2e4f04d3e228412c9b4a4c8809 Mon Sep 17 00:00:00 2001
2 From: Neil Horman <nhorman@tuxdriver.com>
3 Date: Wed, 28 Apr 2010 10:30:59 +0000
4 Subject: sctp: Fix skb_over_panic resulting from multiple invalid parameter errors (CVE-2010-1173) (v4)
5
6 From: Neil Horman <nhorman@tuxdriver.com>
7
8 commit 5fa782c2f5ef6c2e4f04d3e228412c9b4a4c8809 upstream.
9
10 Ok, version 4
11
12 Change Notes:
13 1) Minor cleanups, from Vlads notes
14
15 Summary:
16
17 Hey-
18 Recently, it was reported to me that the kernel could oops in the
19 following way:
20
21 <5> kernel BUG at net/core/skbuff.c:91!
22 <5> invalid operand: 0000 [#1]
23 <5> Modules linked in: sctp netconsole nls_utf8 autofs4 sunrpc iptable_filter
24 ip_tables cpufreq_powersave parport_pc lp parport vmblock(U) vsock(U) vmci(U)
25 vmxnet(U) vmmemctl(U) vmhgfs(U) acpiphp dm_mirror dm_mod button battery ac md5
26 ipv6 uhci_hcd ehci_hcd snd_ens1371 snd_rawmidi snd_seq_device snd_pcm_oss
27 snd_mixer_oss snd_pcm snd_timer snd_page_alloc snd_ac97_codec snd soundcore
28 pcnet32 mii floppy ext3 jbd ata_piix libata mptscsih mptsas mptspi mptscsi
29 mptbase sd_mod scsi_mod
30 <5> CPU: 0
31 <5> EIP: 0060:[<c02bff27>] Not tainted VLI
32 <5> EFLAGS: 00010216 (2.6.9-89.0.25.EL)
33 <5> EIP is at skb_over_panic+0x1f/0x2d
34 <5> eax: 0000002c ebx: c033f461 ecx: c0357d96 edx: c040fd44
35 <5> esi: c033f461 edi: df653280 ebp: 00000000 esp: c040fd40
36 <5> ds: 007b es: 007b ss: 0068
37 <5> Process swapper (pid: 0, threadinfo=c040f000 task=c0370be0)
38 <5> Stack: c0357d96 e0c29478 00000084 00000004 c033f461 df653280 d7883180
39 e0c2947d
40 <5> 00000000 00000080 df653490 00000004 de4f1ac0 de4f1ac0 00000004
41 df653490
42 <5> 00000001 e0c2877a 08000800 de4f1ac0 df653490 00000000 e0c29d2e
43 00000004
44 <5> Call Trace:
45 <5> [<e0c29478>] sctp_addto_chunk+0xb0/0x128 [sctp]
46 <5> [<e0c2947d>] sctp_addto_chunk+0xb5/0x128 [sctp]
47 <5> [<e0c2877a>] sctp_init_cause+0x3f/0x47 [sctp]
48 <5> [<e0c29d2e>] sctp_process_unk_param+0xac/0xb8 [sctp]
49 <5> [<e0c29e90>] sctp_verify_init+0xcc/0x134 [sctp]
50 <5> [<e0c20322>] sctp_sf_do_5_1B_init+0x83/0x28e [sctp]
51 <5> [<e0c25333>] sctp_do_sm+0x41/0x77 [sctp]
52 <5> [<c01555a4>] cache_grow+0x140/0x233
53 <5> [<e0c26ba1>] sctp_endpoint_bh_rcv+0xc5/0x108 [sctp]
54 <5> [<e0c2b863>] sctp_inq_push+0xe/0x10 [sctp]
55 <5> [<e0c34600>] sctp_rcv+0x454/0x509 [sctp]
56 <5> [<e084e017>] ipt_hook+0x17/0x1c [iptable_filter]
57 <5> [<c02d005e>] nf_iterate+0x40/0x81
58 <5> [<c02e0bb9>] ip_local_deliver_finish+0x0/0x151
59 <5> [<c02e0c7f>] ip_local_deliver_finish+0xc6/0x151
60 <5> [<c02d0362>] nf_hook_slow+0x83/0xb5
61 <5> [<c02e0bb2>] ip_local_deliver+0x1a2/0x1a9
62 <5> [<c02e0bb9>] ip_local_deliver_finish+0x0/0x151
63 <5> [<c02e103e>] ip_rcv+0x334/0x3b4
64 <5> [<c02c66fd>] netif_receive_skb+0x320/0x35b
65 <5> [<e0a0928b>] init_stall_timer+0x67/0x6a [uhci_hcd]
66 <5> [<c02c67a4>] process_backlog+0x6c/0xd9
67 <5> [<c02c690f>] net_rx_action+0xfe/0x1f8
68 <5> [<c012a7b1>] __do_softirq+0x35/0x79
69 <5> [<c0107efb>] handle_IRQ_event+0x0/0x4f
70 <5> [<c01094de>] do_softirq+0x46/0x4d
71
72 Its an skb_over_panic BUG halt that results from processing an init chunk in
73 which too many of its variable length parameters are in some way malformed.
74
75 The problem is in sctp_process_unk_param:
76 if (NULL == *errp)
77 *errp = sctp_make_op_error_space(asoc, chunk,
78 ntohs(chunk->chunk_hdr->length));
79
80 if (*errp) {
81 sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
82 WORD_ROUND(ntohs(param.p->length)));
83 sctp_addto_chunk(*errp,
84 WORD_ROUND(ntohs(param.p->length)),
85 param.v);
86
87 When we allocate an error chunk, we assume that the worst case scenario requires
88 that we have chunk_hdr->length data allocated, which would be correct nominally,
89 given that we call sctp_addto_chunk for the violating parameter. Unfortunately,
90 we also, in sctp_init_cause insert a sctp_errhdr_t structure into the error
91 chunk, so the worst case situation in which all parameters are in violation
92 requires chunk_hdr->length+(sizeof(sctp_errhdr_t)*param_count) bytes of data.
93
94 The result of this error is that a deliberately malformed packet sent to a
95 listening host can cause a remote DOS, described in CVE-2010-1173:
96 http://cve.mitre.org/cgi-bin/cvename.cgi?name=2010-1173
97
98 I've tested the below fix and confirmed that it fixes the issue. We move to a
99 strategy whereby we allocate a fixed size error chunk and ignore errors we don't
100 have space to report. Tested by me successfully
101
102 Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
103 Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
104 Signed-off-by: David S. Miller <davem@davemloft.net>
105 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
106
107 ---
108 include/net/sctp/structs.h | 1
109 net/sctp/sm_make_chunk.c | 62 +++++++++++++++++++++++++++++++++++++++++----
110 2 files changed, 58 insertions(+), 5 deletions(-)
111
112 --- a/include/net/sctp/structs.h
113 +++ b/include/net/sctp/structs.h
114 @@ -753,6 +753,7 @@ int sctp_user_addto_chunk(struct sctp_ch
115 struct iovec *data);
116 void sctp_chunk_free(struct sctp_chunk *);
117 void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
118 +void *sctp_addto_chunk_fixed(struct sctp_chunk *, int len, const void *data);
119 struct sctp_chunk *sctp_chunkify(struct sk_buff *,
120 const struct sctp_association *,
121 struct sock *);
122 --- a/net/sctp/sm_make_chunk.c
123 +++ b/net/sctp/sm_make_chunk.c
124 @@ -107,7 +107,7 @@ static const struct sctp_paramhdr prsctp
125 __constant_htons(sizeof(struct sctp_paramhdr)),
126 };
127
128 -/* A helper to initialize to initialize an op error inside a
129 +/* A helper to initialize an op error inside a
130 * provided chunk, as most cause codes will be embedded inside an
131 * abort chunk.
132 */
133 @@ -124,6 +124,29 @@ void sctp_init_cause(struct sctp_chunk
134 chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
135 }
136
137 +/* A helper to initialize an op error inside a
138 + * provided chunk, as most cause codes will be embedded inside an
139 + * abort chunk. Differs from sctp_init_cause in that it won't oops
140 + * if there isn't enough space in the op error chunk
141 + */
142 +int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code,
143 + size_t paylen)
144 +{
145 + sctp_errhdr_t err;
146 + __u16 len;
147 +
148 + /* Cause code constants are now defined in network order. */
149 + err.cause = cause_code;
150 + len = sizeof(sctp_errhdr_t) + paylen;
151 + err.length = htons(len);
152 +
153 + if (skb_tailroom(chunk->skb) > len)
154 + return -ENOSPC;
155 + chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk,
156 + sizeof(sctp_errhdr_t),
157 + &err);
158 + return 0;
159 +}
160 /* 3.3.2 Initiation (INIT) (1)
161 *
162 * This chunk is used to initiate a SCTP association between two
163 @@ -1114,6 +1137,24 @@ nodata:
164 return retval;
165 }
166
167 +/* Create an Operation Error chunk of a fixed size,
168 + * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT)
169 + * This is a helper function to allocate an error chunk for
170 + * for those invalid parameter codes in which we may not want
171 + * to report all the errors, if the incomming chunk is large
172 + */
173 +static inline struct sctp_chunk *sctp_make_op_error_fixed(
174 + const struct sctp_association *asoc,
175 + const struct sctp_chunk *chunk)
176 +{
177 + size_t size = asoc ? asoc->pathmtu : 0;
178 +
179 + if (!size)
180 + size = SCTP_DEFAULT_MAXSEGMENT;
181 +
182 + return sctp_make_op_error_space(asoc, chunk, size);
183 +}
184 +
185 /* Create an Operation Error chunk. */
186 struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
187 const struct sctp_chunk *chunk,
188 @@ -1354,6 +1395,18 @@ void *sctp_addto_chunk(struct sctp_chunk
189 return target;
190 }
191
192 +/* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient
193 + * space in the chunk
194 + */
195 +void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
196 + int len, const void *data)
197 +{
198 + if (skb_tailroom(chunk->skb) > len)
199 + return sctp_addto_chunk(chunk, len, data);
200 + else
201 + return NULL;
202 +}
203 +
204 /* Append bytes from user space to the end of a chunk. Will panic if
205 * chunk is not big enough.
206 * Returns a kernel err value.
207 @@ -1957,13 +2010,12 @@ static sctp_ierror_t sctp_process_unk_pa
208 * returning multiple unknown parameters.
209 */
210 if (NULL == *errp)
211 - *errp = sctp_make_op_error_space(asoc, chunk,
212 - ntohs(chunk->chunk_hdr->length));
213 + *errp = sctp_make_op_error_fixed(asoc, chunk);
214
215 if (*errp) {
216 - sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
217 + sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
218 WORD_ROUND(ntohs(param.p->length)));
219 - sctp_addto_chunk(*errp,
220 + sctp_addto_chunk_fixed(*errp,
221 WORD_ROUND(ntohs(param.p->length)),
222 param.v);
223 } else {