xref: /illumos-gate/usr/src/uts/common/os/klpd.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/atomic.h>
30 #include <sys/door.h>
31 #include <sys/proc.h>
32 #include <sys/cred_impl.h>
33 #include <sys/policy.h>
34 #include <sys/priv.h>
35 #include <sys/klpd.h>
36 #include <sys/errno.h>
37 #include <sys/kmem.h>
38 #include <sys/project.h>
39 #include <sys/systm.h>
40 #include <sys/sysmacros.h>
41 #include <sys/pathname.h>
42 #include <sys/varargs.h>
43 #include <sys/zone.h>
44 #include <netinet/in.h>
45 
46 #define	ROUNDUP(a, n) (((a) + ((n) - 1)) & ~((n) - 1))
47 
48 static kmutex_t klpd_mutex;
49 
50 typedef struct klpd_reg {
51 	struct klpd_reg *klpd_next;
52 	struct klpd_reg **klpd_refp;
53 	door_handle_t 	klpd_door;
54 	pid_t		klpd_door_pid;
55 	priv_set_t	klpd_pset;
56 	cred_t		*klpd_cred;
57 	int		klpd_indel;		/* Disabled */
58 	uint32_t	klpd_ref;
59 } klpd_reg_t;
60 
61 
62 /*
63  * This data structure hangs off the credential of a process; the
64  * credential is finalized and cannot be changed; but this structure
65  * can be changed when a new door server for the particular group
66  * needs to be registered.  It is refcounted and shared between
67  * processes with common ancestry.
68  *
69  * The reference count is atomically updated.
70  *
71  * But the registration probably needs to be updated under a lock.
72  */
73 typedef struct credklpd {
74 	kmutex_t	crkl_lock;
75 	klpd_reg_t	*crkl_reg;
76 	uint32_t	crkl_ref;
77 } credklpd_t;
78 
79 klpd_reg_t *klpd_list;
80 
81 static void klpd_unlink(klpd_reg_t *);
82 static int klpd_unreg_dh(door_handle_t);
83 
84 static credklpd_t *crklpd_alloc(void);
85 
86 void crklpd_setreg(credklpd_t *, klpd_reg_t *);
87 
88 extern size_t max_vnode_path;
89 
90 void
91 klpd_rele(klpd_reg_t *p)
92 {
93 	if (atomic_add_32_nv(&p->klpd_ref, -1) == 0) {
94 		if (p->klpd_refp != NULL)
95 			klpd_unlink(p);
96 		if (p->klpd_cred != NULL)
97 			crfree(p->klpd_cred);
98 		door_ki_rele(p->klpd_door);
99 		kmem_free(p, sizeof (*p));
100 	}
101 }
102 
103 /*
104  * In order to be able to walk the lists, we can't unlink the entry
105  * until the reference count drops to 0.  If we remove it too soon,
106  * list walkers will terminate when they happen to call a now orphaned
107  * entry.
108  */
109 static klpd_reg_t *
110 klpd_rele_next(klpd_reg_t *p)
111 {
112 	klpd_reg_t *r = p->klpd_next;
113 
114 	klpd_rele(p);
115 	return (r);
116 }
117 
118 
119 static void
120 klpd_hold(klpd_reg_t *p)
121 {
122 	atomic_add_32(&p->klpd_ref, 1);
123 }
124 
125 /*
126  * Remove registration from where it is registered.  Returns next in list.
127  */
128 static void
129 klpd_unlink(klpd_reg_t *p)
130 {
131 	ASSERT(p->klpd_refp == NULL || *p->klpd_refp == p);
132 
133 	if (p->klpd_refp != NULL)
134 		*p->klpd_refp = p->klpd_next;
135 
136 	if (p->klpd_next != NULL)
137 		p->klpd_next->klpd_refp = p->klpd_refp;
138 	p->klpd_refp = NULL;
139 }
140 
141 /*
142  * Remove the head of the klpd list and decrement its refcnt.
143  * The lock guarding the list should be held; this function is
144  * called when we are sure we want to remove the entry from the
145  * list but not so sure that the reference count has dropped back to
146  * 1 and is specifically intended to remove the non-list variants.
147  */
148 void
149 klpd_remove(klpd_reg_t **pp)
150 {
151 	klpd_reg_t *p = *pp;
152 	if (p == NULL)
153 		return;
154 	ASSERT(p->klpd_next == NULL);
155 	klpd_unlink(p);
156 	klpd_rele(p);
157 }
158 
159 /*
160  * Link new entry in list.  The Boolean argument specifies whether this
161  * list can contain only a single item or multiple items.
162  * Returns the entry which needs to be released if single is B_TRUE.
163  */
164 static klpd_reg_t *
165 klpd_link(klpd_reg_t *p, klpd_reg_t **listp, boolean_t single)
166 {
167 	klpd_reg_t *old = *listp;
168 
169 	ASSERT(p->klpd_ref == 1);
170 
171 	ASSERT(old == NULL || *old->klpd_refp == old);
172 	p->klpd_refp = listp;
173 	p->klpd_next = single ? NULL : old;
174 	*listp = p;
175 	if (old != NULL) {
176 		if (single) {
177 			ASSERT(old->klpd_next == NULL);
178 			old->klpd_refp = NULL;
179 			return (old);
180 		} else
181 			old->klpd_refp = &p->klpd_next;
182 	}
183 	return (NULL);
184 }
185 
186 /*
187  * The typical call consists of:
188  *	- priv_set_t
189  *	- some integer data (type, value)
190  * for now, it's just one bit.
191  */
192 static klpd_head_t *
193 klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap)
194 {
195 	char	*comp;
196 	uint_t	type;
197 	vnode_t *vp;
198 	size_t	len = sizeof (priv_set_t) + sizeof (klpd_head_t);
199 	size_t	plen, clen;
200 	int	proto;
201 
202 	klpd_arg_t *kap = NULL;
203 	klpd_head_t *khp;
204 
205 	type = va_arg(ap, uint_t);
206 	switch (type) {
207 	case KLPDARG_NOMORE:
208 		khp = kmem_zalloc(len, KM_SLEEP);
209 		khp->klh_argoff = 0;
210 		break;
211 	case KLPDARG_VNODE:
212 		len += offsetof(klpd_arg_t, kla_str);
213 		vp = va_arg(ap, vnode_t *);
214 		if (vp == NULL)
215 			return (NULL);
216 
217 		comp = va_arg(ap, char *);
218 
219 		if (comp != NULL && *comp != '\0')
220 			clen = strlen(comp) + 1;
221 		else
222 			clen = 0;
223 
224 		len += ROUNDUP(MAXPATHLEN, sizeof (uint_t));
225 		khp = kmem_zalloc(len, KM_SLEEP);
226 
227 		khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t);
228 		kap = KLH_ARG(khp);
229 
230 		if (vnodetopath(crgetzone(p->klpd_cred)->zone_rootvp,
231 		    vp, kap->kla_str, MAXPATHLEN, p->klpd_cred) != 0) {
232 			kmem_free(khp, len);
233 			return (NULL);
234 		}
235 		if (clen != 0) {
236 			plen = strlen(kap->kla_str);
237 			if (plen + clen + 1 >= MAXPATHLEN) {
238 				kmem_free(khp, len);
239 				return (NULL);
240 			}
241 			/* Don't make root into a double "/" */
242 			if (plen <= 2)
243 				plen = 0;
244 			kap->kla_str[plen] = '/';
245 			bcopy(comp, &kap->kla_str[plen + 1], clen);
246 		}
247 		break;
248 	case KLPDARG_PORT:
249 		proto = va_arg(ap, int);
250 		switch (proto) {
251 		case IPPROTO_TCP:	type = KLPDARG_TCPPORT;
252 					break;
253 		case IPPROTO_UDP:	type = KLPDARG_UDPPORT;
254 					break;
255 		case IPPROTO_SCTP:	type = KLPDARG_SCTPPORT;
256 					break;
257 		case PROTO_SDP:		type = KLPDARG_SDPPORT;
258 					break;
259 		}
260 		/* FALLTHROUGH */
261 	case KLPDARG_INT:
262 	case KLPDARG_TCPPORT:
263 	case KLPDARG_UDPPORT:
264 	case KLPDARG_SCTPPORT:
265 	case KLPDARG_SDPPORT:
266 		len += sizeof (*kap);
267 		khp = kmem_zalloc(len, KM_SLEEP);
268 		khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t);
269 		kap = KLH_ARG(khp);
270 		kap->kla_int = va_arg(ap, int);
271 		break;
272 	default:
273 		return (NULL);
274 	}
275 	khp->klh_vers = KLPDCALL_VERS;
276 	khp->klh_len = len;
277 	khp->klh_privoff = sizeof (*khp);
278 	*KLH_PRIVSET(khp) = *rq;
279 	if (kap != NULL) {
280 		kap->kla_type = type;
281 		kap->kla_dlen = len - khp->klh_argoff;
282 	}
283 	return (khp);
284 }
285 
286 static int
287 klpd_do_call(klpd_reg_t *p, const priv_set_t *req, va_list ap)
288 {
289 	door_arg_t da;
290 	int res;
291 	int dres;
292 	klpd_head_t *klh;
293 
294 	if (p->klpd_door_pid == curproc->p_pid)
295 		return (-1);
296 
297 	klh = klpd_marshall(p, req, ap);
298 
299 	if (klh == NULL)
300 		return (-1);
301 
302 	da.data_ptr = (char *)klh;
303 	da.data_size = klh->klh_len;
304 	da.desc_ptr = NULL;
305 	da.desc_num = 0;
306 	da.rbuf = (char *)&res;
307 	da.rsize = sizeof (res);
308 
309 	while ((dres = door_ki_upcall_limited(p->klpd_door, &da, NULL,
310 	    SIZE_MAX, 0)) != 0) {
311 		switch (dres) {
312 		case EAGAIN:
313 			delay(1);
314 			continue;
315 		case EINVAL:
316 		case EBADF:
317 			/* Bad door, don't call it again. */
318 			(void) klpd_unreg_dh(p->klpd_door);
319 			/* FALLTHROUGH */
320 		case EINTR:
321 			/* Pending signal, nothing we can do. */
322 			/* FALLTHROUGH */
323 		default:
324 			kmem_free(klh, klh->klh_len);
325 			return (-1);
326 		}
327 	}
328 	kmem_free(klh, klh->klh_len);
329 	/* Bogus return value, must be a failure */
330 	if (da.rbuf != (char *)&res) {
331 		kmem_free(da.rbuf, da.rsize);
332 		return (-1);
333 	}
334 	return (res);
335 }
336 
337 uint32_t klpd_bad_locks;
338 
339 int
340 klpd_call(const cred_t *cr, const priv_set_t *req, va_list ap)
341 {
342 	klpd_reg_t *p;
343 	int rv = -1;
344 	credklpd_t *ckp;
345 	zone_t *ckzone;
346 
347 	/*
348 	 * These locks must not be held when this code is called;
349 	 * callbacks to userland with these locks held will result
350 	 * in issues.  That said, the code at the call sides was
351 	 * restructured not to call with any of the locks held and
352 	 * no policies operate by default on most processes.
353 	 */
354 	if (mutex_owned(&pidlock) || mutex_owned(&curproc->p_lock) ||
355 	    mutex_owned(&curproc->p_crlock)) {
356 		atomic_add_32(&klpd_bad_locks, 1);
357 		return (-1);
358 	}
359 
360 	/*
361 	 * Enforce the limit set for the call process (still).
362 	 */
363 	if (!priv_issubset(req, &CR_LPRIV(cr)))
364 		return (-1);
365 
366 	/* Try 1: get the credential specific klpd */
367 	if ((ckp = crgetcrklpd(cr)) != NULL) {
368 		mutex_enter(&ckp->crkl_lock);
369 		if ((p = ckp->crkl_reg) != NULL &&
370 		    p->klpd_indel == 0 &&
371 		    priv_issubset(req, &p->klpd_pset)) {
372 			klpd_hold(p);
373 			mutex_exit(&ckp->crkl_lock);
374 			rv = klpd_do_call(p, req, ap);
375 			mutex_enter(&ckp->crkl_lock);
376 			klpd_rele(p);
377 			mutex_exit(&ckp->crkl_lock);
378 			if (rv != -1)
379 				return (rv == 0 ? 0 : -1);
380 		} else {
381 			mutex_exit(&ckp->crkl_lock);
382 		}
383 	}
384 
385 	/* Try 2: get the project specific klpd */
386 	mutex_enter(&klpd_mutex);
387 
388 	if ((p = curproj->kpj_klpd) != NULL) {
389 		klpd_hold(p);
390 		mutex_exit(&klpd_mutex);
391 		if (p->klpd_indel == 0 &&
392 		    priv_issubset(req, &p->klpd_pset)) {
393 			rv = klpd_do_call(p, req, ap);
394 		}
395 		mutex_enter(&klpd_mutex);
396 		klpd_rele(p);
397 		mutex_exit(&klpd_mutex);
398 
399 		if (rv != -1)
400 			return (rv == 0 ? 0 : -1);
401 	} else {
402 		mutex_exit(&klpd_mutex);
403 	}
404 
405 	/* Try 3: get the global klpd list */
406 	ckzone = crgetzone(cr);
407 	mutex_enter(&klpd_mutex);
408 
409 	for (p = klpd_list; p != NULL; ) {
410 		zone_t *kkzone = crgetzone(p->klpd_cred);
411 		if ((kkzone == &zone0 || kkzone == ckzone) &&
412 		    p->klpd_indel == 0 &&
413 		    priv_issubset(req, &p->klpd_pset)) {
414 			klpd_hold(p);
415 			mutex_exit(&klpd_mutex);
416 			rv = klpd_do_call(p, req, ap);
417 			mutex_enter(&klpd_mutex);
418 
419 			p = klpd_rele_next(p);
420 
421 			if (rv != -1)
422 				break;
423 		} else {
424 			p = p->klpd_next;
425 		}
426 	}
427 	mutex_exit(&klpd_mutex);
428 	return (rv == 0 ? 0 : -1);
429 }
430 
431 /*
432  * Register the klpd.
433  * If the pid_t passed in is positive, update the registration for
434  * the specific process; that is only possible if the process already
435  * has a registration on it.  This change of registration will affect
436  * all processes which share common ancestry.
437  *
438  * MY_PID (pid 0) can be used to create or change the context for
439  * the current process, typically done after fork().
440  *
441  * A negative value can be used to register a klpd globally.
442  *
443  * The per-credential klpd needs to be cleaned up when entering
444  * a zone or unsetting the flag.
445  */
446 int
447 klpd_reg(int did, idtype_t type, id_t id, priv_set_t *psetbuf)
448 {
449 	cred_t *cr = CRED();
450 	door_handle_t dh;
451 	klpd_reg_t *kpd;
452 	priv_set_t pset;
453 	door_info_t di;
454 	credklpd_t *ckp = NULL;
455 	pid_t pid = -1;
456 	projid_t proj = -1;
457 	kproject_t *kpp = NULL;
458 
459 	if (CR_FLAGS(cr) & PRIV_XPOLICY)
460 		return (set_errno(EINVAL));
461 
462 	if (copyin(psetbuf, &pset, sizeof (priv_set_t)))
463 		return (set_errno(EFAULT));
464 
465 	if (!priv_issubset(&pset, &CR_OEPRIV(cr)))
466 		return (set_errno(EPERM));
467 
468 	switch (type) {
469 	case P_PID:
470 		pid = (pid_t)id;
471 		if (pid == P_MYPID)
472 			pid = curproc->p_pid;
473 		if (pid == curproc->p_pid)
474 			ckp = crklpd_alloc();
475 		break;
476 	case P_PROJID:
477 		proj = (projid_t)id;
478 		kpp = project_hold_by_id(proj, crgetzone(cr),
479 		    PROJECT_HOLD_FIND);
480 		if (kpp == NULL)
481 			return (set_errno(ESRCH));
482 		break;
483 	default:
484 		return (set_errno(ENOTSUP));
485 	}
486 
487 
488 	/*
489 	 * Verify the door passed in; it must be a door and we won't
490 	 * allow processes to be called on their own behalf.
491 	 */
492 	dh = door_ki_lookup(did);
493 	if (dh == NULL || door_ki_info(dh, &di) != 0) {
494 		if (ckp != NULL)
495 			crklpd_rele(ckp);
496 		if (kpp != NULL)
497 			project_rele(kpp);
498 		return (set_errno(EBADF));
499 	}
500 	if (type == P_PID && pid == di.di_target) {
501 		if (ckp != NULL)
502 			crklpd_rele(ckp);
503 		ASSERT(kpp == NULL);
504 		return (set_errno(EINVAL));
505 	}
506 
507 	kpd = kmem_zalloc(sizeof (*kpd), KM_SLEEP);
508 	crhold(kpd->klpd_cred = cr);
509 	kpd->klpd_door = dh;
510 	kpd->klpd_door_pid = di.di_target;
511 	kpd->klpd_ref = 1;
512 	kpd->klpd_pset = pset;
513 
514 	if (kpp != NULL) {
515 		mutex_enter(&klpd_mutex);
516 		kpd = klpd_link(kpd, &kpp->kpj_klpd, B_TRUE);
517 		mutex_exit(&klpd_mutex);
518 		if (kpd != NULL)
519 			klpd_rele(kpd);
520 		project_rele(kpp);
521 	} else if ((int)pid < 0) {
522 		/* Global daemon */
523 		mutex_enter(&klpd_mutex);
524 		(void) klpd_link(kpd, &klpd_list, B_FALSE);
525 		mutex_exit(&klpd_mutex);
526 	} else if (pid == curproc->p_pid) {
527 		proc_t *p = curproc;
528 		cred_t *newcr = cralloc();
529 
530 		/* No need to lock, sole reference to ckp */
531 		kpd = klpd_link(kpd, &ckp->crkl_reg, B_TRUE);
532 
533 		if (kpd != NULL)
534 			klpd_rele(kpd);
535 
536 		mutex_enter(&p->p_crlock);
537 		cr = p->p_cred;
538 		crdup_to(cr, newcr);
539 		crsetcrklpd(newcr, ckp);
540 		p->p_cred = newcr;	/* Already held for p_cred */
541 
542 		crhold(newcr);		/* Hold once for the current thread */
543 		mutex_exit(&p->p_crlock);
544 		crfree(cr);		/* One for the p_cred */
545 		crset(p, newcr);
546 	} else {
547 		proc_t *p;
548 		cred_t *pcr;
549 		mutex_enter(&pidlock);
550 		p = prfind(pid);
551 		if (p == NULL || !prochasprocperm(p, curproc, CRED())) {
552 			mutex_exit(&pidlock);
553 			klpd_rele(kpd);
554 			return (set_errno(p == NULL ? ESRCH : EPERM));
555 		}
556 		mutex_enter(&p->p_crlock);
557 		crhold(pcr = p->p_cred);
558 		mutex_exit(&pidlock);
559 		mutex_exit(&p->p_crlock);
560 		/*
561 		 * We're going to update the credential's ckp in place;
562 		 * this requires that it exists.
563 		 */
564 		ckp = crgetcrklpd(pcr);
565 		if (ckp == NULL) {
566 			crfree(pcr);
567 			klpd_rele(kpd);
568 			return (set_errno(EINVAL));
569 		}
570 		crklpd_setreg(ckp, kpd);
571 		crfree(pcr);
572 	}
573 
574 	return (0);
575 }
576 
577 static int
578 klpd_unreg_dh(door_handle_t dh)
579 {
580 	klpd_reg_t *p;
581 
582 	mutex_enter(&klpd_mutex);
583 	for (p = klpd_list; p != NULL; p = p->klpd_next) {
584 		if (p->klpd_door == dh)
585 			break;
586 	}
587 	if (p == NULL) {
588 		mutex_exit(&klpd_mutex);
589 		return (EINVAL);
590 	}
591 	if (p->klpd_indel != 0) {
592 		mutex_exit(&klpd_mutex);
593 		return (EAGAIN);
594 	}
595 	p->klpd_indel = 1;
596 	klpd_rele(p);
597 	mutex_exit(&klpd_mutex);
598 	return (0);
599 }
600 
601 int
602 klpd_unreg(int did, idtype_t type, id_t id)
603 {
604 	door_handle_t dh;
605 	int res = 0;
606 	proc_t *p;
607 	pid_t pid;
608 	projid_t proj;
609 	kproject_t *kpp = NULL;
610 	credklpd_t *ckp;
611 
612 	switch (type) {
613 	case P_PID:
614 		pid = (pid_t)id;
615 		break;
616 	case P_PROJID:
617 		proj = (projid_t)id;
618 		kpp = project_hold_by_id(proj, crgetzone(CRED()),
619 		    PROJECT_HOLD_FIND);
620 		if (kpp == NULL)
621 			return (set_errno(ESRCH));
622 		break;
623 	default:
624 		return (set_errno(ENOTSUP));
625 	}
626 
627 	dh = door_ki_lookup(did);
628 	if (dh == NULL) {
629 		if (kpp != NULL)
630 			project_rele(kpp);
631 		return (set_errno(EINVAL));
632 	}
633 
634 	if (kpp != NULL) {
635 		mutex_enter(&klpd_mutex);
636 		if (kpp->kpj_klpd == NULL)
637 			res = ESRCH;
638 		else
639 			klpd_remove(&kpp->kpj_klpd);
640 		mutex_exit(&klpd_mutex);
641 		project_rele(kpp);
642 		goto out;
643 	} else if ((int)pid > 0) {
644 		mutex_enter(&pidlock);
645 		p = prfind(pid);
646 		if (p == NULL) {
647 			mutex_exit(&pidlock);
648 			door_ki_rele(dh);
649 			return (set_errno(ESRCH));
650 		}
651 		mutex_enter(&p->p_crlock);
652 		mutex_exit(&pidlock);
653 	} else if (pid == 0) {
654 		p = curproc;
655 		mutex_enter(&p->p_crlock);
656 	} else {
657 		res = klpd_unreg_dh(dh);
658 		goto out;
659 	}
660 
661 	ckp = crgetcrklpd(p->p_cred);
662 	if (ckp != NULL) {
663 		crklpd_setreg(ckp, NULL);
664 	} else {
665 		res = ESRCH;
666 	}
667 	mutex_exit(&p->p_crlock);
668 
669 out:
670 	door_ki_rele(dh);
671 
672 	if (res != 0)
673 		return (set_errno(res));
674 	return (0);
675 }
676 
677 void
678 crklpd_hold(credklpd_t *crkpd)
679 {
680 	atomic_add_32(&crkpd->crkl_ref, 1);
681 }
682 
683 void
684 crklpd_rele(credklpd_t *crkpd)
685 {
686 	if (atomic_add_32_nv(&crkpd->crkl_ref, -1) == 0) {
687 		if (crkpd->crkl_reg != NULL)
688 			klpd_rele(crkpd->crkl_reg);
689 		mutex_destroy(&crkpd->crkl_lock);
690 		kmem_free(crkpd, sizeof (*crkpd));
691 	}
692 }
693 
694 static credklpd_t *
695 crklpd_alloc(void)
696 {
697 	credklpd_t *res = kmem_alloc(sizeof (*res), KM_SLEEP);
698 
699 	mutex_init(&res->crkl_lock, NULL, MUTEX_DEFAULT, NULL);
700 	res->crkl_ref = 1;
701 	res->crkl_reg = NULL;
702 
703 	return (res);
704 }
705 
706 void
707 crklpd_setreg(credklpd_t *crk, klpd_reg_t *new)
708 {
709 	klpd_reg_t *old;
710 
711 	mutex_enter(&crk->crkl_lock);
712 	if (new == NULL) {
713 		old = crk->crkl_reg;
714 		if (old != NULL)
715 			klpd_unlink(old);
716 	} else {
717 		old = klpd_link(new, &crk->crkl_reg, B_TRUE);
718 	}
719 	mutex_exit(&crk->crkl_lock);
720 
721 	if (old != NULL)
722 		klpd_rele(old);
723 }
724