xref: /freebsd/sys/kern/kern_jaildesc.c (revision d8d5324ef5335dd9404db7263be2271610245e10)
1851dc7f8SJamie Gritton /*-
2851dc7f8SJamie Gritton  * SPDX-License-Identifier: BSD-2-Clause
3851dc7f8SJamie Gritton  *
4851dc7f8SJamie Gritton  * Copyright (c) 2025 James Gritton.
5851dc7f8SJamie Gritton  * All rights reserved.
6851dc7f8SJamie Gritton  *
7851dc7f8SJamie Gritton  * Redistribution and use in source and binary forms, with or without
8851dc7f8SJamie Gritton  * modification, are permitted provided that the following conditions
9851dc7f8SJamie Gritton  * are met:
10851dc7f8SJamie Gritton  * 1. Redistributions of source code must retain the above copyright
11851dc7f8SJamie Gritton  *    notice, this list of conditions and the following disclaimer.
12851dc7f8SJamie Gritton  * 2. Redistributions in binary form must reproduce the above copyright
13851dc7f8SJamie Gritton  *    notice, this list of conditions and the following disclaimer in the
14851dc7f8SJamie Gritton  *    documentation and/or other materials provided with the distribution.
15851dc7f8SJamie Gritton  *
16851dc7f8SJamie Gritton  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17851dc7f8SJamie Gritton  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18851dc7f8SJamie Gritton  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19851dc7f8SJamie Gritton  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20851dc7f8SJamie Gritton  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21851dc7f8SJamie Gritton  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22851dc7f8SJamie Gritton  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23851dc7f8SJamie Gritton  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24851dc7f8SJamie Gritton  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25851dc7f8SJamie Gritton  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26851dc7f8SJamie Gritton  * SUCH DAMAGE.
27851dc7f8SJamie Gritton  */
28851dc7f8SJamie Gritton 
29851dc7f8SJamie Gritton #include <sys/param.h>
30851dc7f8SJamie Gritton #include <sys/fcntl.h>
31851dc7f8SJamie Gritton #include <sys/file.h>
32851dc7f8SJamie Gritton #include <sys/filedesc.h>
33851dc7f8SJamie Gritton #include <sys/kernel.h>
34851dc7f8SJamie Gritton #include <sys/jail.h>
35851dc7f8SJamie Gritton #include <sys/jaildesc.h>
36851dc7f8SJamie Gritton #include <sys/lock.h>
37851dc7f8SJamie Gritton #include <sys/malloc.h>
38851dc7f8SJamie Gritton #include <sys/mutex.h>
39851dc7f8SJamie Gritton #include <sys/priv.h>
40851dc7f8SJamie Gritton #include <sys/stat.h>
41851dc7f8SJamie Gritton #include <sys/sysproto.h>
42851dc7f8SJamie Gritton #include <sys/systm.h>
43851dc7f8SJamie Gritton #include <sys/ucred.h>
44851dc7f8SJamie Gritton #include <sys/vnode.h>
45851dc7f8SJamie Gritton 
46851dc7f8SJamie Gritton MALLOC_DEFINE(M_JAILDESC, "jaildesc", "jail descriptors");
47851dc7f8SJamie Gritton 
48851dc7f8SJamie Gritton static fo_stat_t	jaildesc_stat;
49851dc7f8SJamie Gritton static fo_close_t	jaildesc_close;
50851dc7f8SJamie Gritton static fo_chmod_t	jaildesc_chmod;
51851dc7f8SJamie Gritton static fo_chown_t	jaildesc_chown;
52851dc7f8SJamie Gritton static fo_fill_kinfo_t	jaildesc_fill_kinfo;
53851dc7f8SJamie Gritton static fo_cmp_t		jaildesc_cmp;
54851dc7f8SJamie Gritton 
55851dc7f8SJamie Gritton static struct fileops jaildesc_ops = {
56851dc7f8SJamie Gritton 	.fo_read = invfo_rdwr,
57851dc7f8SJamie Gritton 	.fo_write = invfo_rdwr,
58851dc7f8SJamie Gritton 	.fo_truncate = invfo_truncate,
59851dc7f8SJamie Gritton 	.fo_ioctl = invfo_ioctl,
60851dc7f8SJamie Gritton 	.fo_poll = invfo_poll,
61851dc7f8SJamie Gritton 	.fo_kqfilter = invfo_kqfilter,
62851dc7f8SJamie Gritton 	.fo_stat = jaildesc_stat,
63851dc7f8SJamie Gritton 	.fo_close = jaildesc_close,
64851dc7f8SJamie Gritton 	.fo_chmod = jaildesc_chmod,
65851dc7f8SJamie Gritton 	.fo_chown = jaildesc_chown,
66851dc7f8SJamie Gritton 	.fo_sendfile = invfo_sendfile,
67851dc7f8SJamie Gritton 	.fo_fill_kinfo = jaildesc_fill_kinfo,
68851dc7f8SJamie Gritton 	.fo_cmp = jaildesc_cmp,
69851dc7f8SJamie Gritton 	.fo_flags = DFLAG_PASSABLE,
70851dc7f8SJamie Gritton };
71851dc7f8SJamie Gritton 
72851dc7f8SJamie Gritton /*
73851dc7f8SJamie Gritton  * Given a jail descriptor number, return the jaildesc, its prison,
74851dc7f8SJamie Gritton  * and its credential.  The jaildesc will be returned locked, and
75851dc7f8SJamie Gritton  * prison and the credential will be returned held.
76851dc7f8SJamie Gritton  */
77851dc7f8SJamie Gritton int
78851dc7f8SJamie Gritton jaildesc_find(struct thread *td, int fd, struct jaildesc **jdp,
79851dc7f8SJamie Gritton     struct prison **prp, struct ucred **ucredp)
80851dc7f8SJamie Gritton {
81851dc7f8SJamie Gritton 	struct file *fp;
82851dc7f8SJamie Gritton 	struct jaildesc *jd;
83851dc7f8SJamie Gritton 	struct prison *pr;
84851dc7f8SJamie Gritton 	int error;
85851dc7f8SJamie Gritton 
86851dc7f8SJamie Gritton 	error = fget(td, fd, &cap_no_rights, &fp);
87851dc7f8SJamie Gritton 	if (error != 0)
88851dc7f8SJamie Gritton 		return (error);
89851dc7f8SJamie Gritton 	if (fp->f_type != DTYPE_JAILDESC) {
9016f600dcSJamie Gritton 		error = EINVAL;
91851dc7f8SJamie Gritton 		goto out;
92851dc7f8SJamie Gritton 	}
93851dc7f8SJamie Gritton 	jd = fp->f_data;
94851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd);
95851dc7f8SJamie Gritton 	pr = jd->jd_prison;
96851dc7f8SJamie Gritton 	if (pr == NULL || !prison_isvalid(pr)) {
97851dc7f8SJamie Gritton 		error = ENOENT;
98851dc7f8SJamie Gritton 		JAILDESC_UNLOCK(jd);
99851dc7f8SJamie Gritton 		goto out;
100851dc7f8SJamie Gritton 	}
101851dc7f8SJamie Gritton 	prison_hold(pr);
102851dc7f8SJamie Gritton 	*prp = pr;
103851dc7f8SJamie Gritton 	if (jdp != NULL)
104851dc7f8SJamie Gritton 		*jdp = jd;
105851dc7f8SJamie Gritton 	else
106851dc7f8SJamie Gritton 		JAILDESC_UNLOCK(jd);
107851dc7f8SJamie Gritton 	if (ucredp != NULL)
108851dc7f8SJamie Gritton 		*ucredp = crhold(fp->f_cred);
109851dc7f8SJamie Gritton  out:
110851dc7f8SJamie Gritton 	fdrop(fp, td);
111851dc7f8SJamie Gritton 	return (error);
112851dc7f8SJamie Gritton }
113851dc7f8SJamie Gritton 
114851dc7f8SJamie Gritton /*
115851dc7f8SJamie Gritton  * Allocate a new jail decriptor, not yet associated with a prison.
116851dc7f8SJamie Gritton  * Return the file pointer (with a reference held) and the descriptor
117851dc7f8SJamie Gritton  * number.
118851dc7f8SJamie Gritton  */
119851dc7f8SJamie Gritton int
120851dc7f8SJamie Gritton jaildesc_alloc(struct thread *td, struct file **fpp, int *fdp, int owning)
121851dc7f8SJamie Gritton {
122851dc7f8SJamie Gritton 	struct file *fp;
123851dc7f8SJamie Gritton 	struct jaildesc *jd;
124851dc7f8SJamie Gritton 	int error;
125851dc7f8SJamie Gritton 	mode_t mode;
126851dc7f8SJamie Gritton 
127851dc7f8SJamie Gritton 	if (owning) {
128851dc7f8SJamie Gritton 		error = priv_check(td, PRIV_JAIL_REMOVE);
129851dc7f8SJamie Gritton 		if (error != 0)
130851dc7f8SJamie Gritton 			return (error);
131851dc7f8SJamie Gritton 		mode = S_ISTXT;
132851dc7f8SJamie Gritton 	} else
133851dc7f8SJamie Gritton 		mode = 0;
134851dc7f8SJamie Gritton 	jd = malloc(sizeof(*jd), M_JAILDESC, M_WAITOK | M_ZERO);
135851dc7f8SJamie Gritton 	error = falloc_caps(td, &fp, fdp, 0, NULL);
136851dc7f8SJamie Gritton 	if (error != 0) {
137851dc7f8SJamie Gritton 		free(jd, M_JAILDESC);
138851dc7f8SJamie Gritton 		return (error);
139851dc7f8SJamie Gritton 	}
140*d8d5324eSJamie Gritton 	finit(fp, priv_check_cred(fp->f_cred, PRIV_JAIL_SET) == 0 ?
141*d8d5324eSJamie Gritton 	    FREAD | FWRITE : FREAD, DTYPE_JAILDESC, jd, &jaildesc_ops);
142851dc7f8SJamie Gritton 	JAILDESC_LOCK_INIT(jd);
143851dc7f8SJamie Gritton 	jd->jd_uid = fp->f_cred->cr_uid;
144851dc7f8SJamie Gritton 	jd->jd_gid = fp->f_cred->cr_gid;
145*d8d5324eSJamie Gritton 	jd->jd_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | mode |
146*d8d5324eSJamie Gritton 	    (priv_check(td, PRIV_JAIL_SET) == 0 ? S_IWUSR | S_IXUSR : 0) |
147*d8d5324eSJamie Gritton 	    (priv_check(td, PRIV_JAIL_ATTACH) == 0 ? S_IXUSR : 0);
148851dc7f8SJamie Gritton 	*fpp = fp;
149851dc7f8SJamie Gritton 	return (0);
150851dc7f8SJamie Gritton }
151851dc7f8SJamie Gritton 
152851dc7f8SJamie Gritton /*
153851dc7f8SJamie Gritton  * Assocate a jail descriptor with its prison.
154851dc7f8SJamie Gritton  */
155851dc7f8SJamie Gritton void
156851dc7f8SJamie Gritton jaildesc_set_prison(struct file *fp, struct prison *pr)
157851dc7f8SJamie Gritton {
158851dc7f8SJamie Gritton 	struct jaildesc *jd;
159851dc7f8SJamie Gritton 
160851dc7f8SJamie Gritton 	mtx_assert(&pr->pr_mtx, MA_OWNED);
161851dc7f8SJamie Gritton 	jd = fp->f_data;
162851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd);
163851dc7f8SJamie Gritton 	jd->jd_prison = pr;
164851dc7f8SJamie Gritton 	LIST_INSERT_HEAD(&pr->pr_descs, jd, jd_list);
165851dc7f8SJamie Gritton 	prison_hold(pr);
166851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd);
167851dc7f8SJamie Gritton }
168851dc7f8SJamie Gritton 
169851dc7f8SJamie Gritton /*
170*d8d5324eSJamie Gritton  * Detach all the jail descriptors from a prison.
171851dc7f8SJamie Gritton  */
172851dc7f8SJamie Gritton void
173851dc7f8SJamie Gritton jaildesc_prison_cleanup(struct prison *pr)
174851dc7f8SJamie Gritton {
175851dc7f8SJamie Gritton 	struct jaildesc *jd;
176851dc7f8SJamie Gritton 
177851dc7f8SJamie Gritton 	mtx_assert(&pr->pr_mtx, MA_OWNED);
178851dc7f8SJamie Gritton 	while ((jd = LIST_FIRST(&pr->pr_descs))) {
179851dc7f8SJamie Gritton 		JAILDESC_LOCK(jd);
180851dc7f8SJamie Gritton 		LIST_REMOVE(jd, jd_list);
181851dc7f8SJamie Gritton 		jd->jd_prison = NULL;
182851dc7f8SJamie Gritton 		JAILDESC_UNLOCK(jd);
183851dc7f8SJamie Gritton 		prison_free(pr);
184851dc7f8SJamie Gritton 	}
185851dc7f8SJamie Gritton }
186851dc7f8SJamie Gritton 
187851dc7f8SJamie Gritton static int
188851dc7f8SJamie Gritton jaildesc_close(struct file *fp, struct thread *td)
189851dc7f8SJamie Gritton {
190851dc7f8SJamie Gritton 	struct jaildesc *jd;
191851dc7f8SJamie Gritton 	struct prison *pr;
192851dc7f8SJamie Gritton 
193851dc7f8SJamie Gritton 	jd = fp->f_data;
194851dc7f8SJamie Gritton 	fp->f_data = NULL;
195851dc7f8SJamie Gritton 	if (jd != NULL) {
196851dc7f8SJamie Gritton 		JAILDESC_LOCK(jd);
197851dc7f8SJamie Gritton 		pr = jd->jd_prison;
198851dc7f8SJamie Gritton 		if (pr != NULL) {
199851dc7f8SJamie Gritton 			/*
200851dc7f8SJamie Gritton 			 * Free or remove the associated prison.
201851dc7f8SJamie Gritton 			 * This requires a second check after re-
202851dc7f8SJamie Gritton 			 * ordering locks.  This jaildesc can remain
203851dc7f8SJamie Gritton 			 * unlocked once we have a prison reference,
204851dc7f8SJamie Gritton 			 * because that prison is the only place that
205851dc7f8SJamie Gritton 			 * still points back to it.
206851dc7f8SJamie Gritton 			 */
207851dc7f8SJamie Gritton 			prison_hold(pr);
208851dc7f8SJamie Gritton 			JAILDESC_UNLOCK(jd);
209851dc7f8SJamie Gritton 			if (jd->jd_mode & S_ISTXT) {
210851dc7f8SJamie Gritton 				sx_xlock(&allprison_lock);
211851dc7f8SJamie Gritton 				prison_lock(pr);
212851dc7f8SJamie Gritton 				if (jd->jd_prison != NULL) {
213851dc7f8SJamie Gritton 					/*
214851dc7f8SJamie Gritton 					 * Unlink the prison, but don't free
215851dc7f8SJamie Gritton 					 * it; that will be done as part of
216851dc7f8SJamie Gritton 					 * of prison_remove.
217851dc7f8SJamie Gritton 					 */
218851dc7f8SJamie Gritton 					LIST_REMOVE(jd, jd_list);
219851dc7f8SJamie Gritton 					prison_remove(pr);
220851dc7f8SJamie Gritton 				} else {
221851dc7f8SJamie Gritton 					prison_unlock(pr);
222851dc7f8SJamie Gritton 					sx_xunlock(&allprison_lock);
223851dc7f8SJamie Gritton 				}
224851dc7f8SJamie Gritton 			} else {
225851dc7f8SJamie Gritton 				prison_lock(pr);
226851dc7f8SJamie Gritton 				if (jd->jd_prison != NULL) {
227851dc7f8SJamie Gritton 					LIST_REMOVE(jd, jd_list);
228851dc7f8SJamie Gritton 					prison_free(pr);
229851dc7f8SJamie Gritton 				}
230851dc7f8SJamie Gritton 				prison_unlock(pr);
231851dc7f8SJamie Gritton 			}
232851dc7f8SJamie Gritton 			prison_free(pr);
233851dc7f8SJamie Gritton 		}
234851dc7f8SJamie Gritton 		JAILDESC_LOCK_DESTROY(jd);
235851dc7f8SJamie Gritton 		free(jd, M_JAILDESC);
236851dc7f8SJamie Gritton 	}
237851dc7f8SJamie Gritton 	return (0);
238851dc7f8SJamie Gritton }
239851dc7f8SJamie Gritton 
240851dc7f8SJamie Gritton static int
241851dc7f8SJamie Gritton jaildesc_stat(struct file *fp, struct stat *sb, struct ucred *active_cred)
242851dc7f8SJamie Gritton {
243851dc7f8SJamie Gritton 	struct jaildesc *jd;
244851dc7f8SJamie Gritton 
245851dc7f8SJamie Gritton 	bzero(sb, sizeof(struct stat));
246851dc7f8SJamie Gritton 	jd = fp->f_data;
247851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd);
248851dc7f8SJamie Gritton 	if (jd->jd_prison != NULL) {
249851dc7f8SJamie Gritton 		sb->st_ino = jd->jd_prison ? jd->jd_prison->pr_id : 0;
250851dc7f8SJamie Gritton 		sb->st_uid = jd->jd_uid;
251851dc7f8SJamie Gritton 		sb->st_gid = jd->jd_gid;
252851dc7f8SJamie Gritton 		sb->st_mode = jd->jd_mode;
253851dc7f8SJamie Gritton 	} else
254851dc7f8SJamie Gritton 		sb->st_mode = S_IFREG;
255851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd);
256851dc7f8SJamie Gritton 	return (0);
257851dc7f8SJamie Gritton }
258851dc7f8SJamie Gritton 
259851dc7f8SJamie Gritton static int
260851dc7f8SJamie Gritton jaildesc_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
261851dc7f8SJamie Gritton     struct thread *td)
262851dc7f8SJamie Gritton {
263851dc7f8SJamie Gritton 	struct jaildesc *jd;
264851dc7f8SJamie Gritton 	int error;
265851dc7f8SJamie Gritton 
266851dc7f8SJamie Gritton 	/* Reject permissions that the creator doesn't have. */
267*d8d5324eSJamie Gritton 	if (((mode & (S_IWUSR | S_IWGRP | S_IWOTH)) &&
268*d8d5324eSJamie Gritton 	    priv_check_cred(fp->f_cred, PRIV_JAIL_SET) != 0) ||
269*d8d5324eSJamie Gritton 	    ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
270*d8d5324eSJamie Gritton 	    priv_check_cred(fp->f_cred, PRIV_JAIL_ATTACH) != 0 &&
271*d8d5324eSJamie Gritton 	    priv_check_cred(fp->f_cred, PRIV_JAIL_SET) != 0) ||
272*d8d5324eSJamie Gritton 	    ((mode & S_ISTXT) &&
273*d8d5324eSJamie Gritton 	    priv_check_cred(fp->f_cred, PRIV_JAIL_REMOVE) != 0))
274851dc7f8SJamie Gritton 		return (EPERM);
275851dc7f8SJamie Gritton 	if (mode & (S_ISUID | S_ISGID))
276851dc7f8SJamie Gritton 		return (EINVAL);
277851dc7f8SJamie Gritton 	jd = fp->f_data;
278851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd);
279851dc7f8SJamie Gritton 	error = vaccess(VREG, jd->jd_mode, jd->jd_uid, jd->jd_gid, VADMIN,
280851dc7f8SJamie Gritton 		active_cred);
281851dc7f8SJamie Gritton 	if (error == 0)
282851dc7f8SJamie Gritton 		jd->jd_mode = S_IFREG | (mode & ALLPERMS);
283851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd);
284851dc7f8SJamie Gritton 	return (error);
285851dc7f8SJamie Gritton }
286851dc7f8SJamie Gritton 
287851dc7f8SJamie Gritton static int
288851dc7f8SJamie Gritton jaildesc_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
289851dc7f8SJamie Gritton     struct thread *td)
290851dc7f8SJamie Gritton {
291851dc7f8SJamie Gritton 	struct jaildesc *jd;
292851dc7f8SJamie Gritton 	int error;
293851dc7f8SJamie Gritton 
294851dc7f8SJamie Gritton 	error = 0;
295851dc7f8SJamie Gritton 	jd = fp->f_data;
296851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd);
297851dc7f8SJamie Gritton 	if (uid == (uid_t)-1)
298851dc7f8SJamie Gritton 		uid = jd->jd_uid;
299851dc7f8SJamie Gritton 	if (gid == (gid_t)-1)
300851dc7f8SJamie Gritton 		gid = jd->jd_gid;
301851dc7f8SJamie Gritton 	if ((uid != jd->jd_uid && uid != active_cred->cr_uid) ||
302851dc7f8SJamie Gritton 	    (gid != jd->jd_gid && !groupmember(gid, active_cred)))
303851dc7f8SJamie Gritton 		error = priv_check_cred(active_cred, PRIV_VFS_CHOWN);
304851dc7f8SJamie Gritton 	if (error == 0) {
305851dc7f8SJamie Gritton 		jd->jd_uid = uid;
306851dc7f8SJamie Gritton 		jd->jd_gid = gid;
307851dc7f8SJamie Gritton 	}
308851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd);
309851dc7f8SJamie Gritton 	return (error);
310851dc7f8SJamie Gritton }
311851dc7f8SJamie Gritton 
312851dc7f8SJamie Gritton static int
313851dc7f8SJamie Gritton jaildesc_fill_kinfo(struct file *fp, struct kinfo_file *kif,
314851dc7f8SJamie Gritton     struct filedesc *fdp)
315851dc7f8SJamie Gritton {
316851dc7f8SJamie Gritton 	return (EINVAL);
317851dc7f8SJamie Gritton }
318851dc7f8SJamie Gritton 
319851dc7f8SJamie Gritton static int
320851dc7f8SJamie Gritton jaildesc_cmp(struct file *fp1, struct file *fp2, struct thread *td)
321851dc7f8SJamie Gritton {
322851dc7f8SJamie Gritton 	struct jaildesc *jd1, *jd2;
323851dc7f8SJamie Gritton 	int jid1, jid2;
324851dc7f8SJamie Gritton 
325851dc7f8SJamie Gritton 	if (fp2->f_type != DTYPE_JAILDESC)
326851dc7f8SJamie Gritton 		return (3);
327851dc7f8SJamie Gritton 	jd1 = fp1->f_data;
328851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd1);
329851dc7f8SJamie Gritton 	jid1 = jd1->jd_prison ? (uintptr_t)jd1->jd_prison->pr_id : 0;
330851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd1);
331851dc7f8SJamie Gritton 	jd2 = fp2->f_data;
332851dc7f8SJamie Gritton 	JAILDESC_LOCK(jd2);
333851dc7f8SJamie Gritton 	jid2 = jd2->jd_prison ? (uintptr_t)jd2->jd_prison->pr_id : 0;
334851dc7f8SJamie Gritton 	JAILDESC_UNLOCK(jd2);
335851dc7f8SJamie Gritton 	return (kcmp_cmp(jid1, jid2));
336851dc7f8SJamie Gritton }
337