xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_error.c (revision 0bb073995ac5a95bd35f2dd790df1ea3d8c2d507)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 #include <sys/stream.h>
30 #include <sys/cmn_err.h>
31 #include <sys/ddi.h>
32 #include <sys/strsubr.h>
33 #include <sys/tsol/tnet.h>
34 
35 #include <netinet/in.h>
36 #include <netinet/ip6.h>
37 
38 #include <inet/common.h>
39 #include <inet/ip.h>
40 #include <inet/ip6.h>
41 #include <inet/mib2.h>
42 #include <inet/sctp_ip.h>
43 #include <inet/ipclassifier.h>
44 #include <inet/ip_ire.h>
45 #include "sctp_impl.h"
46 #include "sctp_asconf.h"
47 
48 ssize_t
49 sctp_link_abort(mblk_t *mp, uint16_t serror, char *details, size_t len,
50     int iserror, boolean_t tbit)
51 {
52 	size_t alen;
53 	mblk_t *amp;
54 	sctp_chunk_hdr_t *acp;
55 	sctp_parm_hdr_t *eph;
56 
57 	ASSERT(mp != NULL && mp->b_cont == NULL);
58 
59 	alen = sizeof (*acp) + (serror != 0 ? (sizeof (*eph) + len) : 0);
60 
61 	amp = allocb(alen, BPRI_MED);
62 	if (amp == NULL) {
63 		return (-1);
64 	}
65 
66 	amp->b_wptr = amp->b_rptr + alen;
67 
68 	/* Chunk header */
69 	acp = (sctp_chunk_hdr_t *)amp->b_rptr;
70 	acp->sch_id = iserror ? CHUNK_ERROR : CHUNK_ABORT;
71 	acp->sch_flags = 0;
72 	acp->sch_len = htons(alen);
73 	if (tbit)
74 		SCTP_SET_TBIT(acp);
75 
76 	linkb(mp, amp);
77 
78 	if (serror == 0) {
79 		return (alen);
80 	}
81 
82 	eph = (sctp_parm_hdr_t *)(acp + 1);
83 	eph->sph_type = htons(serror);
84 	eph->sph_len = htons(len + sizeof (*eph));
85 
86 	if (len > 0) {
87 		bcopy(details, eph + 1, len);
88 	}
89 
90 	/* XXX pad */
91 
92 	return (alen);
93 }
94 
95 void
96 sctp_user_abort(sctp_t *sctp, mblk_t *data)
97 {
98 	mblk_t *mp;
99 	int len, hdrlen;
100 	char *cause;
101 	sctp_faddr_t *fp = sctp->sctp_current;
102 	sctp_stack_t	*sctps = sctp->sctp_sctps;
103 
104 	mp = sctp_make_mp(sctp, fp, 0);
105 	if (mp == NULL) {
106 		SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
107 		return;
108 	}
109 
110 	/*
111 	 * Create abort chunk.
112 	 */
113 	if (data) {
114 		if (fp->isv4) {
115 			hdrlen = sctp->sctp_hdr_len;
116 		} else {
117 			hdrlen = sctp->sctp_hdr6_len;
118 		}
119 		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
120 		cause = (char *)data->b_rptr;
121 		len = data->b_wptr - data->b_rptr;
122 
123 		if (len + hdrlen > fp->sfa_pmss) {
124 			len = fp->sfa_pmss - hdrlen;
125 		}
126 	} else {
127 		cause = NULL;
128 		len = 0;
129 	}
130 	/*
131 	 * Since it is a user abort, we should have the sctp_t and hence
132 	 * the correct verification tag.  So we should not set the T-bit
133 	 * in the ABORT.
134 	 */
135 	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
136 	    B_FALSE)) < 0) {
137 		freemsg(mp);
138 		return;
139 	}
140 	sctp_set_iplen(sctp, mp);
141 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
142 	BUMP_LOCAL(sctp->sctp_opkts);
143 	BUMP_LOCAL(sctp->sctp_obchunks);
144 
145 	CONN_INC_REF(sctp->sctp_connp);
146 	mp->b_flag |= MSGHASREF;
147 	IP_PUT(mp, sctp->sctp_connp, fp->isv4);
148 
149 	sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
150 	sctp_clean_death(sctp, ECONNABORTED);
151 }
152 
153 /*
154  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
155  */
156 void
157 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
158     size_t len, mblk_t *inmp, int iserror, boolean_t tbit)
159 {
160 
161 	mblk_t		*hmp;
162 	uint32_t	ip_hdr_len;
163 	ipha_t		*iniph;
164 	ipha_t		*ahiph;
165 	ip6_t		*inip6h;
166 	ip6_t		*ahip6h;
167 	sctp_hdr_t	*sh;
168 	sctp_hdr_t	*insh;
169 	size_t		ahlen;
170 	uchar_t		*p;
171 	ssize_t		alen;
172 	int		isv4;
173 	ire_t		*ire;
174 	irb_t		*irb;
175 	ts_label_t	*tsl;
176 	conn_t		*connp;
177 	cred_t		*cr = NULL;
178 	sctp_stack_t	*sctps = sctp->sctp_sctps;
179 	ip_stack_t	*ipst;
180 
181 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
182 	if (isv4) {
183 		ahlen = sctp->sctp_hdr_len;
184 	} else {
185 		ahlen = sctp->sctp_hdr6_len;
186 	}
187 
188 	/*
189 	 * If this is a labeled system, then check to see if we're allowed to
190 	 * send a response to this particular sender.  If not, then just drop.
191 	 */
192 	if (is_system_labeled() && !tsol_can_reply_error(inmp))
193 		return;
194 
195 	hmp = allocb_cred(sctps->sctps_wroff_xtra + ahlen,
196 	    CONN_CRED(sctp->sctp_connp));
197 	if (hmp == NULL) {
198 		/* XXX no resources */
199 		return;
200 	}
201 
202 	/* copy in the IP / SCTP header */
203 	p = hmp->b_rptr + sctps->sctps_wroff_xtra;
204 	hmp->b_rptr = p;
205 	hmp->b_wptr = p + ahlen;
206 	if (isv4) {
207 		bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
208 		/*
209 		 * Composite is likely incomplete at this point, so pull
210 		 * info from the incoming IP / SCTP headers.
211 		 */
212 		ahiph = (ipha_t *)p;
213 		iniph = (ipha_t *)inmp->b_rptr;
214 		ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
215 
216 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
217 		ASSERT(OK_32PTR(sh));
218 
219 		insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
220 		ASSERT(OK_32PTR(insh));
221 
222 		/* Copy in the peer's IP addr */
223 		ahiph->ipha_dst = iniph->ipha_src;
224 		ahiph->ipha_src = iniph->ipha_dst;
225 	} else {
226 		bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
227 		ahip6h = (ip6_t *)p;
228 		inip6h = (ip6_t *)inmp->b_rptr;
229 		ip_hdr_len = ip_hdr_length_v6(inmp, inip6h);
230 
231 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
232 		ASSERT(OK_32PTR(sh));
233 
234 		insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
235 		ASSERT(OK_32PTR(insh));
236 
237 		/* Copy in the peer's IP addr */
238 		ahip6h->ip6_dst = inip6h->ip6_src;
239 		ahip6h->ip6_src = inip6h->ip6_dst;
240 	}
241 
242 	/* Fill in the holes in the SCTP common header */
243 	sh->sh_sport = insh->sh_dport;
244 	sh->sh_dport = insh->sh_sport;
245 	sh->sh_verf = vtag;
246 
247 	/* Link in the abort chunk */
248 	if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
249 	    < 0) {
250 		freemsg(hmp);
251 		return;
252 	}
253 
254 	if (isv4) {
255 		ahiph->ipha_length = htons(ahlen + alen);
256 	} else {
257 		ahip6h->ip6_plen = htons(alen + sizeof (*sh));
258 	}
259 
260 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
261 	BUMP_LOCAL(sctp->sctp_obchunks);
262 
263 	ipst = sctps->sctps_netstack->netstack_ip;
264 	connp = sctp->sctp_connp;
265 	if (is_system_labeled() && (cr = DB_CRED(inmp)) != NULL &&
266 	    crgetlabel(cr) != NULL) {
267 		int err;
268 		boolean_t exempt = connp->conn_mac_exempt;
269 
270 		if (isv4)
271 			err = tsol_check_label(cr, &hmp, exempt, ipst);
272 		else
273 			err = tsol_check_label_v6(cr, &hmp, exempt, ipst);
274 		if (err != 0) {
275 			freemsg(hmp);
276 			return;
277 		}
278 	}
279 
280 	/* Stash the conn ptr info. for IP */
281 	SCTP_STASH_IPINFO(hmp, NULL);
282 
283 	CONN_INC_REF(connp);
284 	hmp->b_flag |= MSGHASREF;
285 	IP_PUT(hmp, connp, sctp->sctp_current == NULL ? B_TRUE :
286 	    sctp->sctp_current->isv4);
287 	/*
288 	 * Let's just mark the IRE for this destination as temporary
289 	 * to prevent any DoS attack.
290 	 */
291 	tsl = cr == NULL ? NULL : crgetlabel(cr);
292 	if (isv4) {
293 		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid, tsl,
294 		    ipst);
295 	} else {
296 		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid,
297 		    tsl, ipst);
298 	}
299 	/*
300 	 * In the normal case the ire would be non-null, however it could be
301 	 * null, say, if IP needs to resolve the gateway for this address. We
302 	 * only care about IRE_CACHE.
303 	 */
304 	if (ire == NULL)
305 		return;
306 	if (ire->ire_type != IRE_CACHE) {
307 		ire_refrele(ire);
308 		return;
309 	}
310 	irb = ire->ire_bucket;
311 	/* ire_lock is not needed, as ire_marks is protected by irb_lock */
312 	rw_enter(&irb->irb_lock, RW_WRITER);
313 	/*
314 	 * Only increment the temporary IRE count if the original
315 	 * IRE is not already marked temporary.
316 	 */
317 	if (!(ire->ire_marks & IRE_MARK_TEMPORARY)) {
318 		irb->irb_tmp_ire_cnt++;
319 		ire->ire_marks |= IRE_MARK_TEMPORARY;
320 	}
321 	rw_exit(&irb->irb_lock);
322 	ire_refrele(ire);
323 }
324 
325 /*ARGSUSED*/
326 mblk_t *
327 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
328 {
329 
330 	mblk_t *emp;
331 	size_t elen;
332 	sctp_chunk_hdr_t *ecp;
333 	sctp_parm_hdr_t *eph;
334 	int pad;
335 
336 	if ((pad = len % SCTP_ALIGN) != 0) {
337 		pad = SCTP_ALIGN - pad;
338 	}
339 
340 	elen = sizeof (*ecp) + sizeof (*eph) + len;
341 	emp = allocb(elen + pad, BPRI_MED);
342 	if (emp == NULL) {
343 		return (NULL);
344 	}
345 
346 	emp->b_wptr = emp->b_rptr + elen + pad;
347 
348 	/* Chunk header */
349 	ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
350 	ecp->sch_id = CHUNK_ERROR;
351 	ecp->sch_flags = 0;
352 	ecp->sch_len = htons(elen);
353 
354 	eph = (sctp_parm_hdr_t *)(ecp + 1);
355 	eph->sph_type = htons(serror);
356 	eph->sph_len = htons(len + sizeof (*eph));
357 
358 	if (len > 0) {
359 		bcopy(details, eph + 1, len);
360 	}
361 
362 	if (pad != 0) {
363 		bzero((uchar_t *)(eph + 1) + len, pad);
364 	}
365 
366 	return (emp);
367 }
368 
369 /*
370  * Called from sctp_input_data() to add one error chunk to the error
371  * chunks list.  The error chunks list will be processed at the end
372  * of sctp_input_data() by calling sctp_process_err().
373  */
374 void
375 sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
376     sctp_faddr_t *dest)
377 {
378 	sctp_stack_t *sctps = sctp->sctp_sctps;
379 	mblk_t *emp;
380 	uint32_t emp_len;
381 	uint32_t mss;
382 	mblk_t *sendmp;
383 	sctp_faddr_t *fp;
384 
385 	emp = sctp_make_err(sctp, serror, details, len);
386 	if (emp == NULL)
387 		return;
388 	emp_len = MBLKL(emp);
389 	if (sctp->sctp_err_chunks != NULL) {
390 		fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
391 	} else {
392 		fp = dest;
393 		SCTP_SET_CHUNK_DEST(emp, dest);
394 	}
395 	mss = fp->sfa_pmss;
396 
397 	/*
398 	 * If the current output packet cannot include the new error chunk,
399 	 * send out the current packet and then add the new error chunk
400 	 * to the new output packet.
401 	 */
402 	if (sctp->sctp_err_len + emp_len > mss) {
403 		if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
404 			SCTP_KSTAT(sctps, sctp_send_err_failed);
405 			/* Just free the latest error chunk. */
406 			freeb(emp);
407 			return;
408 		}
409 		sendmp->b_cont = sctp->sctp_err_chunks;
410 		sctp_set_iplen(sctp, sendmp);
411 		sctp_add_sendq(sctp, sendmp);
412 
413 		sctp->sctp_err_chunks = emp;
414 		sctp->sctp_err_len = emp_len;
415 		SCTP_SET_CHUNK_DEST(emp, dest);
416 	} else {
417 		if (sctp->sctp_err_chunks != NULL)
418 			linkb(sctp->sctp_err_chunks, emp);
419 		else
420 			sctp->sctp_err_chunks = emp;
421 		sctp->sctp_err_len += emp_len;
422 	}
423 	/* Assume that we will send it out... */
424 	BUMP_LOCAL(sctp->sctp_obchunks);
425 }
426 
427 /*
428  * Called from sctp_input_data() to send out error chunks created during
429  * the processing of all the chunks in an incoming packet.
430  */
431 void
432 sctp_process_err(sctp_t *sctp)
433 {
434 	sctp_stack_t *sctps = sctp->sctp_sctps;
435 	mblk_t *errmp;
436 	mblk_t *sendmp;
437 
438 	ASSERT(sctp->sctp_err_chunks != NULL);
439 	errmp = sctp->sctp_err_chunks;
440 	if ((sendmp = sctp_make_mp(sctp, SCTP_CHUNK_DEST(errmp), 0)) == NULL) {
441 		SCTP_KSTAT(sctps, sctp_send_err_failed);
442 		freemsg(errmp);
443 		goto done;
444 	}
445 	sendmp->b_cont = errmp;
446 	sctp_set_iplen(sctp, sendmp);
447 	sctp_add_sendq(sctp, sendmp);
448 done:
449 	sctp->sctp_err_chunks = NULL;
450 	sctp->sctp_err_len = 0;
451 }
452 
453 /*
454  * Returns 0 on non-fatal error, otherwise a system error on fatal
455  * error.
456  */
457 int
458 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
459     mblk_t *mp)
460 {
461 	sctp_parm_hdr_t *errh;
462 	sctp_chunk_hdr_t *uch;
463 
464 	if (ch->sch_len == htons(sizeof (*ch))) {
465 		/* no error cause given */
466 		return (0);
467 	}
468 	errh = (sctp_parm_hdr_t *)(ch + 1);
469 	sctp_error_event(sctp, ch);
470 
471 	switch (errh->sph_type) {
472 	/*
473 	 * Both BAD_SID and NO_USR_DATA errors
474 	 * indicate a serious bug in our stack,
475 	 * so complain and abort the association.
476 	 */
477 	case SCTP_ERR_BAD_SID:
478 		cmn_err(CE_WARN, "BUG! send to invalid SID");
479 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
480 		return (ECONNABORTED);
481 	case SCTP_ERR_NO_USR_DATA:
482 		cmn_err(CE_WARN, "BUG! no usr data");
483 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
484 		return (ECONNABORTED);
485 	case SCTP_ERR_UNREC_CHUNK:
486 		/* Pull out the unrecognized chunk type */
487 		if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
488 			/* Not enough to process */
489 			return (0);
490 		}
491 		uch = (sctp_chunk_hdr_t *)(errh + 1);
492 		if (uch->sch_id == CHUNK_ASCONF) {
493 			/* Turn on ASCONF sending */
494 			sctp->sctp_understands_asconf = B_FALSE;
495 			/*
496 			 * Hand off to asconf to clear out the unacked
497 			 * asconf chunk.
498 			 */
499 			if (ntohs(uch->sch_len) !=
500 			    (ntohs(errh->sph_len) - sizeof (*errh))) {
501 				/* malformed */
502 				dprint(0, ("Malformed Unrec Chunk error\n"));
503 				return (0);
504 			}
505 			sctp_asconf_free_cxmit(sctp, uch);
506 			return (0);
507 		}
508 		/* Else drop it */
509 		break;
510 	default:
511 		break;
512 	}
513 
514 	return (0);
515 }
516