xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_error.c (revision ef2504f26d1ea5859db9838255bb63f488f1b050)
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 2009 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 	/*
105 	 * Don't need notification if connection is not yet setup,
106 	 * call sctp_clean_death() to reclaim resources.
107 	 * Any pending connect call(s) will error out.
108 	 */
109 	if (sctp->sctp_state < SCTPS_COOKIE_WAIT) {
110 		sctp_clean_death(sctp, ECONNABORTED);
111 		return;
112 	}
113 
114 	mp = sctp_make_mp(sctp, fp, 0);
115 	if (mp == NULL) {
116 		SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
117 		return;
118 	}
119 
120 	/*
121 	 * Create abort chunk.
122 	 */
123 	if (data) {
124 		if (fp->isv4) {
125 			hdrlen = sctp->sctp_hdr_len;
126 		} else {
127 			hdrlen = sctp->sctp_hdr6_len;
128 		}
129 		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
130 		cause = (char *)data->b_rptr;
131 		len = data->b_wptr - data->b_rptr;
132 
133 		if (len + hdrlen > fp->sfa_pmss) {
134 			len = fp->sfa_pmss - hdrlen;
135 		}
136 	} else {
137 		cause = NULL;
138 		len = 0;
139 	}
140 	/*
141 	 * Since it is a user abort, we should have the sctp_t and hence
142 	 * the correct verification tag.  So we should not set the T-bit
143 	 * in the ABORT.
144 	 */
145 	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
146 	    B_FALSE)) < 0) {
147 		freemsg(mp);
148 		return;
149 	}
150 	sctp_set_iplen(sctp, mp);
151 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
152 	BUMP_LOCAL(sctp->sctp_opkts);
153 	BUMP_LOCAL(sctp->sctp_obchunks);
154 
155 	CONN_INC_REF(sctp->sctp_connp);
156 	mp->b_flag |= MSGHASREF;
157 	IP_PUT(mp, sctp->sctp_connp, fp->isv4);
158 
159 	sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
160 	sctp_clean_death(sctp, ECONNABORTED);
161 }
162 
163 /*
164  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
165  */
166 void
167 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
168     size_t len, mblk_t *inmp, int iserror, boolean_t tbit)
169 {
170 
171 	mblk_t		*hmp;
172 	uint32_t	ip_hdr_len;
173 	ipha_t		*iniph;
174 	ipha_t		*ahiph;
175 	ip6_t		*inip6h;
176 	ip6_t		*ahip6h;
177 	sctp_hdr_t	*sh;
178 	sctp_hdr_t	*insh;
179 	size_t		ahlen;
180 	uchar_t		*p;
181 	ssize_t		alen;
182 	int		isv4;
183 	ire_t		*ire;
184 	irb_t		*irb;
185 	ts_label_t	*tsl;
186 	conn_t		*connp;
187 	cred_t		*cr = NULL;
188 	sctp_stack_t	*sctps = sctp->sctp_sctps;
189 	ip_stack_t	*ipst;
190 
191 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
192 	if (isv4) {
193 		ahlen = sctp->sctp_hdr_len;
194 	} else {
195 		ahlen = sctp->sctp_hdr6_len;
196 	}
197 
198 	/*
199 	 * If this is a labeled system, then check to see if we're allowed to
200 	 * send a response to this particular sender.  If not, then just drop.
201 	 */
202 	if (is_system_labeled() && !tsol_can_reply_error(inmp))
203 		return;
204 
205 	hmp = allocb_cred(sctps->sctps_wroff_xtra + ahlen,
206 	    CONN_CRED(sctp->sctp_connp), sctp->sctp_cpid);
207 	if (hmp == NULL) {
208 		/* XXX no resources */
209 		return;
210 	}
211 
212 	/* copy in the IP / SCTP header */
213 	p = hmp->b_rptr + sctps->sctps_wroff_xtra;
214 	hmp->b_rptr = p;
215 	hmp->b_wptr = p + ahlen;
216 	if (isv4) {
217 		bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
218 		/*
219 		 * Composite is likely incomplete at this point, so pull
220 		 * info from the incoming IP / SCTP headers.
221 		 */
222 		ahiph = (ipha_t *)p;
223 		iniph = (ipha_t *)inmp->b_rptr;
224 		ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
225 
226 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
227 		ASSERT(OK_32PTR(sh));
228 
229 		insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
230 		ASSERT(OK_32PTR(insh));
231 
232 		/* Copy in the peer's IP addr */
233 		ahiph->ipha_dst = iniph->ipha_src;
234 		ahiph->ipha_src = iniph->ipha_dst;
235 	} else {
236 		bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
237 		ahip6h = (ip6_t *)p;
238 		inip6h = (ip6_t *)inmp->b_rptr;
239 		ip_hdr_len = ip_hdr_length_v6(inmp, inip6h);
240 
241 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
242 		ASSERT(OK_32PTR(sh));
243 
244 		insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
245 		ASSERT(OK_32PTR(insh));
246 
247 		/* Copy in the peer's IP addr */
248 		ahip6h->ip6_dst = inip6h->ip6_src;
249 		ahip6h->ip6_src = inip6h->ip6_dst;
250 	}
251 
252 	/* Fill in the holes in the SCTP common header */
253 	sh->sh_sport = insh->sh_dport;
254 	sh->sh_dport = insh->sh_sport;
255 	sh->sh_verf = vtag;
256 
257 	/* Link in the abort chunk */
258 	if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
259 	    < 0) {
260 		freemsg(hmp);
261 		return;
262 	}
263 
264 	if (isv4) {
265 		ahiph->ipha_length = htons(ahlen + alen);
266 	} else {
267 		ahip6h->ip6_plen = htons(alen + sizeof (*sh));
268 	}
269 
270 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
271 	BUMP_LOCAL(sctp->sctp_obchunks);
272 
273 	ipst = sctps->sctps_netstack->netstack_ip;
274 	connp = sctp->sctp_connp;
275 	if (is_system_labeled() && (cr = msg_getcred(inmp, NULL)) != NULL &&
276 	    crgetlabel(cr) != NULL) {
277 		int err;
278 		boolean_t exempt = connp->conn_mac_exempt;
279 
280 		if (isv4)
281 			err = tsol_check_label(cr, &hmp, exempt, ipst);
282 		else
283 			err = tsol_check_label_v6(cr, &hmp, exempt, ipst);
284 		if (err != 0) {
285 			freemsg(hmp);
286 			return;
287 		}
288 	}
289 
290 	/* Stash the conn ptr info. for IP */
291 	SCTP_STASH_IPINFO(hmp, NULL);
292 
293 	CONN_INC_REF(connp);
294 	hmp->b_flag |= MSGHASREF;
295 	IP_PUT(hmp, connp, sctp->sctp_current == NULL ? B_TRUE :
296 	    sctp->sctp_current->isv4);
297 	/*
298 	 * Let's just mark the IRE for this destination as temporary
299 	 * to prevent any DoS attack.
300 	 */
301 	tsl = cr == NULL ? NULL : crgetlabel(cr);
302 	if (isv4) {
303 		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid, tsl,
304 		    ipst);
305 	} else {
306 		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid,
307 		    tsl, ipst);
308 	}
309 	/*
310 	 * In the normal case the ire would be non-null, however it could be
311 	 * null, say, if IP needs to resolve the gateway for this address. We
312 	 * only care about IRE_CACHE.
313 	 */
314 	if (ire == NULL)
315 		return;
316 	if (ire->ire_type != IRE_CACHE) {
317 		ire_refrele(ire);
318 		return;
319 	}
320 	irb = ire->ire_bucket;
321 	/* ire_lock is not needed, as ire_marks is protected by irb_lock */
322 	rw_enter(&irb->irb_lock, RW_WRITER);
323 	/*
324 	 * Only increment the temporary IRE count if the original
325 	 * IRE is not already marked temporary.
326 	 */
327 	if (!(ire->ire_marks & IRE_MARK_TEMPORARY)) {
328 		irb->irb_tmp_ire_cnt++;
329 		ire->ire_marks |= IRE_MARK_TEMPORARY;
330 	}
331 	rw_exit(&irb->irb_lock);
332 	ire_refrele(ire);
333 }
334 
335 /*ARGSUSED*/
336 mblk_t *
337 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
338 {
339 
340 	mblk_t *emp;
341 	size_t elen;
342 	sctp_chunk_hdr_t *ecp;
343 	sctp_parm_hdr_t *eph;
344 	int pad;
345 
346 	if ((pad = len % SCTP_ALIGN) != 0) {
347 		pad = SCTP_ALIGN - pad;
348 	}
349 
350 	elen = sizeof (*ecp) + sizeof (*eph) + len;
351 	emp = allocb(elen + pad, BPRI_MED);
352 	if (emp == NULL) {
353 		return (NULL);
354 	}
355 
356 	emp->b_wptr = emp->b_rptr + elen + pad;
357 
358 	/* Chunk header */
359 	ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
360 	ecp->sch_id = CHUNK_ERROR;
361 	ecp->sch_flags = 0;
362 	ecp->sch_len = htons(elen);
363 
364 	eph = (sctp_parm_hdr_t *)(ecp + 1);
365 	eph->sph_type = htons(serror);
366 	eph->sph_len = htons(len + sizeof (*eph));
367 
368 	if (len > 0) {
369 		bcopy(details, eph + 1, len);
370 	}
371 
372 	if (pad != 0) {
373 		bzero((uchar_t *)(eph + 1) + len, pad);
374 	}
375 
376 	return (emp);
377 }
378 
379 /*
380  * Called from sctp_input_data() to add one error chunk to the error
381  * chunks list.  The error chunks list will be processed at the end
382  * of sctp_input_data() by calling sctp_process_err().
383  */
384 void
385 sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
386     sctp_faddr_t *dest)
387 {
388 	sctp_stack_t *sctps = sctp->sctp_sctps;
389 	mblk_t *emp;
390 	uint32_t emp_len;
391 	uint32_t mss;
392 	mblk_t *sendmp;
393 	sctp_faddr_t *fp;
394 
395 	emp = sctp_make_err(sctp, serror, details, len);
396 	if (emp == NULL)
397 		return;
398 	emp_len = MBLKL(emp);
399 	if (sctp->sctp_err_chunks != NULL) {
400 		fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
401 	} else {
402 		fp = dest;
403 		SCTP_SET_CHUNK_DEST(emp, dest);
404 	}
405 	mss = fp->sfa_pmss;
406 
407 	/*
408 	 * If the current output packet cannot include the new error chunk,
409 	 * send out the current packet and then add the new error chunk
410 	 * to the new output packet.
411 	 */
412 	if (sctp->sctp_err_len + emp_len > mss) {
413 		if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
414 			SCTP_KSTAT(sctps, sctp_send_err_failed);
415 			/* Just free the latest error chunk. */
416 			freeb(emp);
417 			return;
418 		}
419 		sendmp->b_cont = sctp->sctp_err_chunks;
420 		sctp_set_iplen(sctp, sendmp);
421 		sctp_add_sendq(sctp, sendmp);
422 
423 		sctp->sctp_err_chunks = emp;
424 		sctp->sctp_err_len = emp_len;
425 		SCTP_SET_CHUNK_DEST(emp, dest);
426 	} else {
427 		if (sctp->sctp_err_chunks != NULL)
428 			linkb(sctp->sctp_err_chunks, emp);
429 		else
430 			sctp->sctp_err_chunks = emp;
431 		sctp->sctp_err_len += emp_len;
432 	}
433 	/* Assume that we will send it out... */
434 	BUMP_LOCAL(sctp->sctp_obchunks);
435 }
436 
437 /*
438  * Called from sctp_input_data() to send out error chunks created during
439  * the processing of all the chunks in an incoming packet.
440  */
441 void
442 sctp_process_err(sctp_t *sctp)
443 {
444 	sctp_stack_t *sctps = sctp->sctp_sctps;
445 	mblk_t *errmp;
446 	mblk_t *sendmp;
447 
448 	ASSERT(sctp->sctp_err_chunks != NULL);
449 	errmp = sctp->sctp_err_chunks;
450 	if ((sendmp = sctp_make_mp(sctp, SCTP_CHUNK_DEST(errmp), 0)) == NULL) {
451 		SCTP_KSTAT(sctps, sctp_send_err_failed);
452 		freemsg(errmp);
453 		goto done;
454 	}
455 	sendmp->b_cont = errmp;
456 	sctp_set_iplen(sctp, sendmp);
457 	sctp_add_sendq(sctp, sendmp);
458 done:
459 	sctp->sctp_err_chunks = NULL;
460 	sctp->sctp_err_len = 0;
461 }
462 
463 /*
464  * Returns 0 on non-fatal error, otherwise a system error on fatal
465  * error.
466  */
467 int
468 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
469     mblk_t *mp)
470 {
471 	sctp_parm_hdr_t *errh;
472 	sctp_chunk_hdr_t *uch;
473 
474 	if (ch->sch_len == htons(sizeof (*ch))) {
475 		/* no error cause given */
476 		return (0);
477 	}
478 	errh = (sctp_parm_hdr_t *)(ch + 1);
479 	sctp_error_event(sctp, ch);
480 
481 	switch (errh->sph_type) {
482 	/*
483 	 * Both BAD_SID and NO_USR_DATA errors
484 	 * indicate a serious bug in our stack,
485 	 * so complain and abort the association.
486 	 */
487 	case SCTP_ERR_BAD_SID:
488 		cmn_err(CE_WARN, "BUG! send to invalid SID");
489 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
490 		return (ECONNABORTED);
491 	case SCTP_ERR_NO_USR_DATA:
492 		cmn_err(CE_WARN, "BUG! no usr data");
493 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
494 		return (ECONNABORTED);
495 	case SCTP_ERR_UNREC_CHUNK:
496 		/* Pull out the unrecognized chunk type */
497 		if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
498 			/* Not enough to process */
499 			return (0);
500 		}
501 		uch = (sctp_chunk_hdr_t *)(errh + 1);
502 		if (uch->sch_id == CHUNK_ASCONF) {
503 			/* Turn on ASCONF sending */
504 			sctp->sctp_understands_asconf = B_FALSE;
505 			/*
506 			 * Hand off to asconf to clear out the unacked
507 			 * asconf chunk.
508 			 */
509 			if (ntohs(uch->sch_len) !=
510 			    (ntohs(errh->sph_len) - sizeof (*errh))) {
511 				/* malformed */
512 				dprint(0, ("Malformed Unrec Chunk error\n"));
513 				return (0);
514 			}
515 			sctp_asconf_free_cxmit(sctp, uch);
516 			return (0);
517 		}
518 		/* Else drop it */
519 		break;
520 	default:
521 		break;
522 	}
523 
524 	return (0);
525 }
526