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