xref: /illumos-gate/usr/src/uts/common/os/klpd.c (revision 374ae87f60894937d3c6e53ec4a739188e702ea5)
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(p->klpd_door, &da)) != 0) {
310 		switch (dres) {
311 		case EAGAIN:
312 			delay(1);
313 			continue;
314 		case EINVAL:
315 		case EBADF:
316 			/* Bad door, don't call it again. */
317 			(void) klpd_unreg_dh(p->klpd_door);
318 			/* FALLTHROUGH */
319 		case EINTR:
320 			/* Pending signal, nothing we can do. */
321 			/* FALLTHROUGH */
322 		default:
323 			kmem_free(klh, klh->klh_len);
324 			return (-1);
325 		}
326 	}
327 	kmem_free(klh, klh->klh_len);
328 	/* Bogus return value, must be a failure */
329 	if (da.rbuf != (char *)&res) {
330 		kmem_free(da.rbuf, da.rsize);
331 		return (-1);
332 	}
333 	return (res);
334 }
335 
336 uint32_t klpd_bad_locks;
337 
338 int
339 klpd_call(const cred_t *cr, const priv_set_t *req, va_list ap)
340 {
341 	klpd_reg_t *p;
342 	int rv = -1;
343 	credklpd_t *ckp;
344 	zone_t *ckzone;
345 
346 	/*
347 	 * These locks must not be held when this code is called;
348 	 * callbacks to userland with these locks held will result
349 	 * in issues.  That said, the code at the call sides was
350 	 * restructured not to call with any of the locks held and
351 	 * no policies operate by default on most processes.
352 	 */
353 	if (mutex_owned(&pidlock) || mutex_owned(&curproc->p_lock) ||
354 	    mutex_owned(&curproc->p_crlock)) {
355 		atomic_add_32(&klpd_bad_locks, 1);
356 		return (-1);
357 	}
358 
359 	/*
360 	 * Enforce the limit set for the call process (still).
361 	 */
362 	if (!priv_issubset(req, &CR_LPRIV(cr)))
363 		return (-1);
364 
365 	/* Try 1: get the credential specific klpd */
366 	if ((ckp = crgetcrklpd(cr)) != NULL) {
367 		mutex_enter(&ckp->crkl_lock);
368 		if ((p = ckp->crkl_reg) != NULL &&
369 		    p->klpd_indel == 0 &&
370 		    priv_issubset(req, &p->klpd_pset)) {
371 			klpd_hold(p);
372 			mutex_exit(&ckp->crkl_lock);
373 			rv = klpd_do_call(p, req, ap);
374 			mutex_enter(&ckp->crkl_lock);
375 			klpd_rele(p);
376 			mutex_exit(&ckp->crkl_lock);
377 			if (rv != -1)
378 				return (rv == 0 ? 0 : -1);
379 		} else {
380 			mutex_exit(&ckp->crkl_lock);
381 		}
382 	}
383 
384 	/* Try 2: get the project specific klpd */
385 	mutex_enter(&klpd_mutex);
386 
387 	if ((p = curproj->kpj_klpd) != NULL) {
388 		klpd_hold(p);
389 		mutex_exit(&klpd_mutex);
390 		if (p->klpd_indel == 0 &&
391 		    priv_issubset(req, &p->klpd_pset)) {
392 			rv = klpd_do_call(p, req, ap);
393 		}
394 		mutex_enter(&klpd_mutex);
395 		klpd_rele(p);
396 		mutex_exit(&klpd_mutex);
397 
398 		if (rv != -1)
399 			return (rv == 0 ? 0 : -1);
400 	} else {
401 		mutex_exit(&klpd_mutex);
402 	}
403 
404 	/* Try 3: get the global klpd list */
405 	ckzone = crgetzone(cr);
406 	mutex_enter(&klpd_mutex);
407 
408 	for (p = klpd_list; p != NULL; ) {
409 		zone_t *kkzone = crgetzone(p->klpd_cred);
410 		if ((kkzone == &zone0 || kkzone == ckzone) &&
411 		    p->klpd_indel == 0 &&
412 		    priv_issubset(req, &p->klpd_pset)) {
413 			klpd_hold(p);
414 			mutex_exit(&klpd_mutex);
415 			rv = klpd_do_call(p, req, ap);
416 			mutex_enter(&klpd_mutex);
417 
418 			p = klpd_rele_next(p);
419 
420 			if (rv != -1)
421 				break;
422 		} else {
423 			p = p->klpd_next;
424 		}
425 	}
426 	mutex_exit(&klpd_mutex);
427 	return (rv == 0 ? 0 : -1);
428 }
429 
430 /*
431  * Register the klpd.
432  * If the pid_t passed in is positive, update the registration for
433  * the specific process; that is only possible if the process already
434  * has a registration on it.  This change of registration will affect
435  * all processes which share common ancestry.
436  *
437  * MY_PID (pid 0) can be used to create or change the context for
438  * the current process, typically done after fork().
439  *
440  * A negative value can be used to register a klpd globally.
441  *
442  * The per-credential klpd needs to be cleaned up when entering
443  * a zone or unsetting the flag.
444  */
445 int
446 klpd_reg(int did, idtype_t type, id_t id, priv_set_t *psetbuf)
447 {
448 	cred_t *cr = CRED();
449 	door_handle_t dh;
450 	klpd_reg_t *kpd;
451 	priv_set_t pset;
452 	door_info_t di;
453 	credklpd_t *ckp = NULL;
454 	pid_t pid = -1;
455 	projid_t proj = -1;
456 	kproject_t *kpp = NULL;
457 
458 	if (CR_FLAGS(cr) & PRIV_XPOLICY)
459 		return (set_errno(EINVAL));
460 
461 	if (copyin(psetbuf, &pset, sizeof (priv_set_t)))
462 		return (set_errno(EFAULT));
463 
464 	if (!priv_issubset(&pset, &CR_OEPRIV(cr)))
465 		return (set_errno(EPERM));
466 
467 	switch (type) {
468 	case P_PID:
469 		pid = (pid_t)id;
470 		if (pid == P_MYPID)
471 			pid = curproc->p_pid;
472 		if (pid == curproc->p_pid)
473 			ckp = crklpd_alloc();
474 		break;
475 	case P_PROJID:
476 		proj = (projid_t)id;
477 		kpp = project_hold_by_id(proj, crgetzone(cr),
478 		    PROJECT_HOLD_FIND);
479 		if (kpp == NULL)
480 			return (set_errno(ESRCH));
481 		break;
482 	default:
483 		return (set_errno(ENOTSUP));
484 	}
485 
486 
487 	/*
488 	 * Verify the door passed in; it must be a door and we won't
489 	 * allow processes to be called on their own behalf.
490 	 */
491 	dh = door_ki_lookup(did);
492 	if (dh == NULL || door_ki_info(dh, &di) != 0) {
493 		if (ckp != NULL)
494 			crklpd_rele(ckp);
495 		if (kpp != NULL)
496 			project_rele(kpp);
497 		return (set_errno(EBADF));
498 	}
499 	if (type == P_PID && pid == di.di_target) {
500 		if (ckp != NULL)
501 			crklpd_rele(ckp);
502 		ASSERT(kpp == NULL);
503 		return (set_errno(EINVAL));
504 	}
505 
506 	kpd = kmem_zalloc(sizeof (*kpd), KM_SLEEP);
507 	crhold(kpd->klpd_cred = cr);
508 	kpd->klpd_door = dh;
509 	kpd->klpd_door_pid = di.di_target;
510 	kpd->klpd_ref = 1;
511 	kpd->klpd_pset = pset;
512 
513 	if (kpp != NULL) {
514 		mutex_enter(&klpd_mutex);
515 		kpd = klpd_link(kpd, &kpp->kpj_klpd, B_TRUE);
516 		mutex_exit(&klpd_mutex);
517 		if (kpd != NULL)
518 			klpd_rele(kpd);
519 		project_rele(kpp);
520 	} else if ((int)pid < 0) {
521 		/* Global daemon */
522 		mutex_enter(&klpd_mutex);
523 		(void) klpd_link(kpd, &klpd_list, B_FALSE);
524 		mutex_exit(&klpd_mutex);
525 	} else if (pid == curproc->p_pid) {
526 		proc_t *p = curproc;
527 		cred_t *newcr = cralloc();
528 
529 		/* No need to lock, sole reference to ckp */
530 		kpd = klpd_link(kpd, &ckp->crkl_reg, B_TRUE);
531 
532 		if (kpd != NULL)
533 			klpd_rele(kpd);
534 
535 		mutex_enter(&p->p_crlock);
536 		cr = p->p_cred;
537 		crdup_to(cr, newcr);
538 		crsetcrklpd(newcr, ckp);
539 		p->p_cred = newcr;	/* Already held for p_cred */
540 
541 		crhold(newcr);		/* Hold once for the current thread */
542 		mutex_exit(&p->p_crlock);
543 		crfree(cr);		/* One for the p_cred */
544 		crset(p, newcr);
545 	} else {
546 		proc_t *p;
547 		cred_t *pcr;
548 		mutex_enter(&pidlock);
549 		p = prfind(pid);
550 		if (p == NULL || !prochasprocperm(p, curproc, CRED())) {
551 			mutex_exit(&pidlock);
552 			klpd_rele(kpd);
553 			return (set_errno(p == NULL ? ESRCH : EPERM));
554 		}
555 		mutex_enter(&p->p_crlock);
556 		crhold(pcr = p->p_cred);
557 		mutex_exit(&pidlock);
558 		mutex_exit(&p->p_crlock);
559 		/*
560 		 * We're going to update the credential's ckp in place;
561 		 * this requires that it exists.
562 		 */
563 		ckp = crgetcrklpd(pcr);
564 		if (ckp == NULL) {
565 			crfree(pcr);
566 			klpd_rele(kpd);
567 			return (set_errno(EINVAL));
568 		}
569 		crklpd_setreg(ckp, kpd);
570 		crfree(pcr);
571 	}
572 
573 	return (0);
574 }
575 
576 static int
577 klpd_unreg_dh(door_handle_t dh)
578 {
579 	klpd_reg_t *p;
580 
581 	mutex_enter(&klpd_mutex);
582 	for (p = klpd_list; p != NULL; p = p->klpd_next) {
583 		if (p->klpd_door == dh)
584 			break;
585 	}
586 	if (p == NULL) {
587 		mutex_exit(&klpd_mutex);
588 		return (EINVAL);
589 	}
590 	if (p->klpd_indel != 0) {
591 		mutex_exit(&klpd_mutex);
592 		return (EAGAIN);
593 	}
594 	p->klpd_indel = 1;
595 	klpd_rele(p);
596 	mutex_exit(&klpd_mutex);
597 	return (0);
598 }
599 
600 int
601 klpd_unreg(int did, idtype_t type, id_t id)
602 {
603 	door_handle_t dh;
604 	int res = 0;
605 	proc_t *p;
606 	pid_t pid;
607 	projid_t proj;
608 	kproject_t *kpp = NULL;
609 	credklpd_t *ckp;
610 
611 	switch (type) {
612 	case P_PID:
613 		pid = (pid_t)id;
614 		break;
615 	case P_PROJID:
616 		proj = (projid_t)id;
617 		kpp = project_hold_by_id(proj, crgetzone(CRED()),
618 		    PROJECT_HOLD_FIND);
619 		if (kpp == NULL)
620 			return (set_errno(ESRCH));
621 		break;
622 	default:
623 		return (set_errno(ENOTSUP));
624 	}
625 
626 	dh = door_ki_lookup(did);
627 	if (dh == NULL) {
628 		if (kpp != NULL)
629 			project_rele(kpp);
630 		return (set_errno(EINVAL));
631 	}
632 
633 	if (kpp != NULL) {
634 		mutex_enter(&klpd_mutex);
635 		if (kpp->kpj_klpd == NULL)
636 			res = ESRCH;
637 		else
638 			klpd_remove(&kpp->kpj_klpd);
639 		mutex_exit(&klpd_mutex);
640 		project_rele(kpp);
641 		goto out;
642 	} else if ((int)pid > 0) {
643 		mutex_enter(&pidlock);
644 		p = prfind(pid);
645 		if (p == NULL) {
646 			mutex_exit(&pidlock);
647 			door_ki_rele(dh);
648 			return (set_errno(ESRCH));
649 		}
650 		mutex_enter(&p->p_crlock);
651 		mutex_exit(&pidlock);
652 	} else if (pid == 0) {
653 		p = curproc;
654 		mutex_enter(&p->p_crlock);
655 	} else {
656 		res = klpd_unreg_dh(dh);
657 		goto out;
658 	}
659 
660 	ckp = crgetcrklpd(p->p_cred);
661 	if (ckp != NULL) {
662 		crklpd_setreg(ckp, NULL);
663 	} else {
664 		res = ESRCH;
665 	}
666 	mutex_exit(&p->p_crlock);
667 
668 out:
669 	door_ki_rele(dh);
670 
671 	if (res != 0)
672 		return (set_errno(res));
673 	return (0);
674 }
675 
676 void
677 crklpd_hold(credklpd_t *crkpd)
678 {
679 	atomic_add_32(&crkpd->crkl_ref, 1);
680 }
681 
682 void
683 crklpd_rele(credklpd_t *crkpd)
684 {
685 	if (atomic_add_32_nv(&crkpd->crkl_ref, -1) == 0) {
686 		if (crkpd->crkl_reg != NULL)
687 			klpd_rele(crkpd->crkl_reg);
688 		mutex_destroy(&crkpd->crkl_lock);
689 		kmem_free(crkpd, sizeof (*crkpd));
690 	}
691 }
692 
693 static credklpd_t *
694 crklpd_alloc(void)
695 {
696 	credklpd_t *res = kmem_alloc(sizeof (*res), KM_SLEEP);
697 
698 	mutex_init(&res->crkl_lock, NULL, MUTEX_DEFAULT, NULL);
699 	res->crkl_ref = 1;
700 	res->crkl_reg = NULL;
701 
702 	return (res);
703 }
704 
705 void
706 crklpd_setreg(credklpd_t *crk, klpd_reg_t *new)
707 {
708 	klpd_reg_t *old;
709 
710 	mutex_enter(&crk->crkl_lock);
711 	if (new == NULL) {
712 		old = crk->crkl_reg;
713 		if (old != NULL)
714 			klpd_unlink(old);
715 	} else {
716 		old = klpd_link(new, &crk->crkl_reg, B_TRUE);
717 	}
718 	mutex_exit(&crk->crkl_lock);
719 
720 	if (old != NULL)
721 		klpd_rele(old);
722 }
723