Deleted Added
full compact
kern_jail.c (168399) kern_jail.c (168401)
1/*-
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10#include <sys/cdefs.h>
1/*-
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 168399 2007-04-05 21:34:54Z pjd $");
11__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 168401 2007-04-05 23:19:13Z pjd $");
12
13#include "opt_mac.h"
14
15#include <sys/param.h>
16#include <sys/types.h>
17#include <sys/kernel.h>
18#include <sys/systm.h>
19#include <sys/errno.h>
20#include <sys/sysproto.h>
21#include <sys/malloc.h>
22#include <sys/priv.h>
23#include <sys/proc.h>
24#include <sys/taskqueue.h>
25#include <sys/jail.h>
26#include <sys/lock.h>
27#include <sys/mutex.h>
12
13#include "opt_mac.h"
14
15#include <sys/param.h>
16#include <sys/types.h>
17#include <sys/kernel.h>
18#include <sys/systm.h>
19#include <sys/errno.h>
20#include <sys/sysproto.h>
21#include <sys/malloc.h>
22#include <sys/priv.h>
23#include <sys/proc.h>
24#include <sys/taskqueue.h>
25#include <sys/jail.h>
26#include <sys/lock.h>
27#include <sys/mutex.h>
28#include <sys/sx.h>
28#include <sys/namei.h>
29#include <sys/mount.h>
30#include <sys/queue.h>
31#include <sys/socket.h>
32#include <sys/syscallsubr.h>
33#include <sys/sysctl.h>
34#include <sys/vnode.h>
35#include <net/if.h>

--- 36 unchanged lines hidden (view full) ---

72 &jail_chflags_allowed, 0,
73 "Processes in jail can alter system file flags");
74
75int jail_mount_allowed = 0;
76SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
77 &jail_mount_allowed, 0,
78 "Processes in jail can mount/unmount jail-friendly file systems");
79
29#include <sys/namei.h>
30#include <sys/mount.h>
31#include <sys/queue.h>
32#include <sys/socket.h>
33#include <sys/syscallsubr.h>
34#include <sys/sysctl.h>
35#include <sys/vnode.h>
36#include <net/if.h>

--- 36 unchanged lines hidden (view full) ---

73 &jail_chflags_allowed, 0,
74 "Processes in jail can alter system file flags");
75
76int jail_mount_allowed = 0;
77SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
78 &jail_mount_allowed, 0,
79 "Processes in jail can mount/unmount jail-friendly file systems");
80
80/* allprison, lastprid, and prisoncount are protected by allprison_mtx. */
81/* allprison, lastprid, and prisoncount are protected by allprison_lock. */
81struct prisonlist allprison;
82struct prisonlist allprison;
82struct mtx allprison_mtx;
83struct sx allprison_lock;
83int lastprid = 0;
84int prisoncount = 0;
85
84int lastprid = 0;
85int prisoncount = 0;
86
87/*
88 * List of jail services. Protected by allprison_lock.
89 */
90TAILQ_HEAD(prison_services_head, prison_service);
91static struct prison_services_head prison_services =
92 TAILQ_HEAD_INITIALIZER(prison_services);
93static int prison_service_slots = 0;
94
95struct prison_service {
96 prison_create_t ps_create;
97 prison_destroy_t ps_destroy;
98 int ps_slotno;
99 TAILQ_ENTRY(prison_service) ps_next;
100 char ps_name[0];
101};
102
86static void init_prison(void *);
87static void prison_complete(void *context, int pending);
88static int sysctl_jail_list(SYSCTL_HANDLER_ARGS);
89
90static void
91init_prison(void *data __unused)
92{
93
103static void init_prison(void *);
104static void prison_complete(void *context, int pending);
105static int sysctl_jail_list(SYSCTL_HANDLER_ARGS);
106
107static void
108init_prison(void *data __unused)
109{
110
94 mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF);
111 sx_init(&allprison_lock, "allprison");
95 LIST_INIT(&allprison);
96}
97
98SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
99
100/*
101 * struct jail_args {
102 * struct jail *jail;
103 * };
104 */
105int
106jail(struct thread *td, struct jail_args *uap)
107{
108 struct nameidata nd;
109 struct prison *pr, *tpr;
112 LIST_INIT(&allprison);
113}
114
115SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
116
117/*
118 * struct jail_args {
119 * struct jail *jail;
120 * };
121 */
122int
123jail(struct thread *td, struct jail_args *uap)
124{
125 struct nameidata nd;
126 struct prison *pr, *tpr;
127 struct prison_service *psrv;
110 struct jail j;
111 struct jail_attach_args jaa;
112 int vfslocked, error, tryprid;
113
114 error = copyin(uap->jail, &j, sizeof(j));
115 if (error)
116 return (error);
117 if (j.version != 0)

--- 16 unchanged lines hidden (view full) ---

134 NDFREE(&nd, NDF_ONLY_PNBUF);
135 VFS_UNLOCK_GIANT(vfslocked);
136 error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
137 if (error)
138 goto e_dropvnref;
139 pr->pr_ip = j.ip_number;
140 pr->pr_linux = NULL;
141 pr->pr_securelevel = securelevel;
128 struct jail j;
129 struct jail_attach_args jaa;
130 int vfslocked, error, tryprid;
131
132 error = copyin(uap->jail, &j, sizeof(j));
133 if (error)
134 return (error);
135 if (j.version != 0)

--- 16 unchanged lines hidden (view full) ---

152 NDFREE(&nd, NDF_ONLY_PNBUF);
153 VFS_UNLOCK_GIANT(vfslocked);
154 error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
155 if (error)
156 goto e_dropvnref;
157 pr->pr_ip = j.ip_number;
158 pr->pr_linux = NULL;
159 pr->pr_securelevel = securelevel;
160 if (prison_service_slots == 0)
161 pr->pr_slots = NULL;
162 else {
163 pr->pr_slots = malloc(sizeof(*pr->pr_slots) * prison_service_slots,
164 M_PRISON, M_ZERO | M_WAITOK);
165 }
142
143 /* Determine next pr_id and add prison to allprison list. */
166
167 /* Determine next pr_id and add prison to allprison list. */
144 mtx_lock(&allprison_mtx);
168 sx_xlock(&allprison_lock);
145 tryprid = lastprid + 1;
146 if (tryprid == JAIL_MAX)
147 tryprid = 1;
148next:
149 LIST_FOREACH(tpr, &allprison, pr_list) {
150 if (tpr->pr_id == tryprid) {
151 tryprid++;
152 if (tryprid == JAIL_MAX) {
169 tryprid = lastprid + 1;
170 if (tryprid == JAIL_MAX)
171 tryprid = 1;
172next:
173 LIST_FOREACH(tpr, &allprison, pr_list) {
174 if (tpr->pr_id == tryprid) {
175 tryprid++;
176 if (tryprid == JAIL_MAX) {
153 mtx_unlock(&allprison_mtx);
177 sx_xunlock(&allprison_lock);
154 error = EAGAIN;
155 goto e_dropvnref;
156 }
157 goto next;
158 }
159 }
160 pr->pr_id = jaa.jid = lastprid = tryprid;
161 LIST_INSERT_HEAD(&allprison, pr, pr_list);
162 prisoncount++;
178 error = EAGAIN;
179 goto e_dropvnref;
180 }
181 goto next;
182 }
183 }
184 pr->pr_id = jaa.jid = lastprid = tryprid;
185 LIST_INSERT_HEAD(&allprison, pr, pr_list);
186 prisoncount++;
163 mtx_unlock(&allprison_mtx);
187 sx_downgrade(&allprison_lock);
188 TAILQ_FOREACH(psrv, &prison_services, ps_next) {
189 psrv->ps_create(psrv, pr);
190 }
191 sx_sunlock(&allprison_lock);
164
165 error = jail_attach(td, &jaa);
166 if (error)
167 goto e_dropprref;
168 mtx_lock(&pr->pr_mtx);
169 pr->pr_ref--;
170 mtx_unlock(&pr->pr_mtx);
171 td->td_retval[0] = jaa.jid;
172 return (0);
173e_dropprref:
192
193 error = jail_attach(td, &jaa);
194 if (error)
195 goto e_dropprref;
196 mtx_lock(&pr->pr_mtx);
197 pr->pr_ref--;
198 mtx_unlock(&pr->pr_mtx);
199 td->td_retval[0] = jaa.jid;
200 return (0);
201e_dropprref:
174 mtx_lock(&allprison_mtx);
202 sx_xlock(&allprison_lock);
175 LIST_REMOVE(pr, pr_list);
176 prisoncount--;
203 LIST_REMOVE(pr, pr_list);
204 prisoncount--;
177 mtx_unlock(&allprison_mtx);
205 sx_downgrade(&allprison_lock);
206 TAILQ_FOREACH(psrv, &prison_services, ps_next) {
207 psrv->ps_destroy(psrv, pr);
208 }
209 sx_sunlock(&allprison_lock);
178e_dropvnref:
179 vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
180 vrele(pr->pr_root);
181 VFS_UNLOCK_GIANT(vfslocked);
182e_killmtx:
183 mtx_destroy(&pr->pr_mtx);
184 FREE(pr, M_PRISON);
185 return (error);

--- 20 unchanged lines hidden (view full) ---

206 * a process root from one prison, but attached to the jail
207 * of another.
208 */
209 error = priv_check(td, PRIV_JAIL_ATTACH);
210 if (error)
211 return (error);
212
213 p = td->td_proc;
210e_dropvnref:
211 vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
212 vrele(pr->pr_root);
213 VFS_UNLOCK_GIANT(vfslocked);
214e_killmtx:
215 mtx_destroy(&pr->pr_mtx);
216 FREE(pr, M_PRISON);
217 return (error);

--- 20 unchanged lines hidden (view full) ---

238 * a process root from one prison, but attached to the jail
239 * of another.
240 */
241 error = priv_check(td, PRIV_JAIL_ATTACH);
242 if (error)
243 return (error);
244
245 p = td->td_proc;
214 mtx_lock(&allprison_mtx);
246 sx_slock(&allprison_lock);
215 pr = prison_find(uap->jid);
216 if (pr == NULL) {
247 pr = prison_find(uap->jid);
248 if (pr == NULL) {
217 mtx_unlock(&allprison_mtx);
249 sx_sunlock(&allprison_lock);
218 return (EINVAL);
219 }
220 pr->pr_ref++;
221 mtx_unlock(&pr->pr_mtx);
250 return (EINVAL);
251 }
252 pr->pr_ref++;
253 mtx_unlock(&pr->pr_mtx);
222 mtx_unlock(&allprison_mtx);
254 sx_sunlock(&allprison_lock);
223
224 vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
225 vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td);
226 if ((error = change_dir(pr->pr_root, td)) != 0)
227 goto e_unlock;
228#ifdef MAC
229 if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root)))
230 goto e_unlock;

--- 24 unchanged lines hidden (view full) ---

255/*
256 * Returns a locked prison instance, or NULL on failure.
257 */
258struct prison *
259prison_find(int prid)
260{
261 struct prison *pr;
262
255
256 vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
257 vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td);
258 if ((error = change_dir(pr->pr_root, td)) != 0)
259 goto e_unlock;
260#ifdef MAC
261 if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root)))
262 goto e_unlock;

--- 24 unchanged lines hidden (view full) ---

287/*
288 * Returns a locked prison instance, or NULL on failure.
289 */
290struct prison *
291prison_find(int prid)
292{
293 struct prison *pr;
294
263 mtx_assert(&allprison_mtx, MA_OWNED);
295 sx_assert(&allprison_lock, SX_LOCKED);
264 LIST_FOREACH(pr, &allprison, pr_list) {
265 if (pr->pr_id == prid) {
266 mtx_lock(&pr->pr_mtx);
267 return (pr);
268 }
269 }
270 return (NULL);
271}
272
273void
274prison_free(struct prison *pr)
275{
296 LIST_FOREACH(pr, &allprison, pr_list) {
297 if (pr->pr_id == prid) {
298 mtx_lock(&pr->pr_mtx);
299 return (pr);
300 }
301 }
302 return (NULL);
303}
304
305void
306prison_free(struct prison *pr)
307{
308 struct prison_service *psrv;
276
309
277 mtx_lock(&allprison_mtx);
310 sx_xlock(&allprison_lock);
278 mtx_lock(&pr->pr_mtx);
279 pr->pr_ref--;
280 if (pr->pr_ref == 0) {
281 LIST_REMOVE(pr, pr_list);
282 mtx_unlock(&pr->pr_mtx);
283 prisoncount--;
311 mtx_lock(&pr->pr_mtx);
312 pr->pr_ref--;
313 if (pr->pr_ref == 0) {
314 LIST_REMOVE(pr, pr_list);
315 mtx_unlock(&pr->pr_mtx);
316 prisoncount--;
284 mtx_unlock(&allprison_mtx);
317 sx_downgrade(&allprison_lock);
318 TAILQ_FOREACH(psrv, &prison_services, ps_next) {
319 psrv->ps_destroy(psrv, pr);
320 }
321 sx_sunlock(&allprison_lock);
285
286 TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
287 taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
288 return;
289 }
290 mtx_unlock(&pr->pr_mtx);
322
323 TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
324 taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
325 return;
326 }
327 mtx_unlock(&pr->pr_mtx);
291 mtx_unlock(&allprison_mtx);
328 sx_xunlock(&allprison_lock);
292}
293
294static void
295prison_complete(void *context, int pending)
296{
297 struct prison *pr;
298 int vfslocked;
299

--- 395 unchanged lines hidden (view full) ---

695 * In all remaining cases, deny the privilege request. This
696 * includes almost all network privileges, many system
697 * configuration privileges.
698 */
699 return (EPERM);
700 }
701}
702
329}
330
331static void
332prison_complete(void *context, int pending)
333{
334 struct prison *pr;
335 int vfslocked;
336

--- 395 unchanged lines hidden (view full) ---

732 * In all remaining cases, deny the privilege request. This
733 * includes almost all network privileges, many system
734 * configuration privileges.
735 */
736 return (EPERM);
737 }
738}
739
740/*
741 * Register jail service. Provides 'create' and 'destroy' methods.
742 * 'create' method will be called for every existing jail and all
743 * jails in the future as they beeing created.
744 * 'destroy' method will be called for every jail going away and
745 * for all existing jails at the time of service deregistration.
746 */
747struct prison_service *
748prison_service_register(const char *name, prison_create_t create,
749 prison_destroy_t destroy)
750{
751 struct prison_service *psrv, *psrv2;
752 struct prison *pr;
753 int reallocate = 1, slotno = 0;
754 void **slots, **oldslots;
755
756 psrv = malloc(sizeof(*psrv) + strlen(name) + 1, M_PRISON,
757 M_WAITOK | M_ZERO);
758 psrv->ps_create = create;
759 psrv->ps_destroy = destroy;
760 strcpy(psrv->ps_name, name);
761 /*
762 * Grab the allprison_lock here, so we won't miss any jail
763 * creation/destruction.
764 */
765 sx_xlock(&allprison_lock);
766#ifdef INVARIANTS
767 /*
768 * Verify if service is not already registered.
769 */
770 TAILQ_FOREACH(psrv2, &prison_services, ps_next) {
771 KASSERT(strcmp(psrv2->ps_name, name) != 0,
772 ("jail service %s already registered", name));
773 }
774#endif
775 /*
776 * Find free slot. When there is no existing free slot available,
777 * allocate one at the end.
778 */
779 TAILQ_FOREACH(psrv2, &prison_services, ps_next) {
780 if (psrv2->ps_slotno != slotno) {
781 KASSERT(slotno < psrv2->ps_slotno,
782 ("Invalid slotno (slotno=%d >= ps_slotno=%d",
783 slotno, psrv2->ps_slotno));
784 /* We found free slot. */
785 reallocate = 0;
786 break;
787 }
788 slotno++;
789 }
790 psrv->ps_slotno = slotno;
791 /*
792 * Keep the list sorted by slot number.
793 */
794 if (psrv2 != NULL) {
795 KASSERT(reallocate == 0, ("psrv2 != NULL && reallocate != 0"));
796 TAILQ_INSERT_BEFORE(psrv2, psrv, ps_next);
797 } else {
798 KASSERT(reallocate == 1, ("psrv2 == NULL && reallocate == 0"));
799 TAILQ_INSERT_TAIL(&prison_services, psrv, ps_next);
800 }
801 prison_service_slots++;
802 sx_downgrade(&allprison_lock);
803 /*
804 * Allocate memory for new slot if we didn't found empty one.
805 * Do not use realloc(9), because pr_slots is protected with a mutex,
806 * so we can't sleep.
807 */
808 LIST_FOREACH(pr, &allprison, pr_list) {
809 if (reallocate) {
810 /* First allocate memory with M_WAITOK. */
811 slots = malloc(sizeof(*slots) * prison_service_slots,
812 M_PRISON, M_WAITOK);
813 /* Now grab the mutex and replace pr_slots. */
814 mtx_lock(&pr->pr_mtx);
815 oldslots = pr->pr_slots;
816 if (psrv->ps_slotno > 0) {
817 bcopy(oldslots, slots,
818 sizeof(*slots) * (prison_service_slots - 1));
819 }
820 slots[psrv->ps_slotno] = NULL;
821 pr->pr_slots = slots;
822 mtx_unlock(&pr->pr_mtx);
823 if (oldslots != NULL)
824 free(oldslots, M_PRISON);
825 }
826 /*
827 * Call 'create' method for each existing jail.
828 */
829 psrv->ps_create(psrv, pr);
830 }
831 sx_sunlock(&allprison_lock);
832
833 return (psrv);
834}
835
836void
837prison_service_deregister(struct prison_service *psrv)
838{
839 struct prison *pr;
840 void **slots, **oldslots;
841 int last = 0;
842
843 sx_xlock(&allprison_lock);
844 if (TAILQ_LAST(&prison_services, prison_services_head) == psrv)
845 last = 1;
846 TAILQ_REMOVE(&prison_services, psrv, ps_next);
847 prison_service_slots--;
848 sx_downgrade(&allprison_lock);
849 LIST_FOREACH(pr, &allprison, pr_list) {
850 /*
851 * Call 'destroy' method for every currently existing jail.
852 */
853 psrv->ps_destroy(psrv, pr);
854 /*
855 * If this is the last slot, free the memory allocated for it.
856 */
857 if (last) {
858 if (prison_service_slots == 0)
859 slots = NULL;
860 else {
861 slots = malloc(sizeof(*slots) * prison_service_slots,
862 M_PRISON, M_WAITOK);
863 }
864 mtx_lock(&pr->pr_mtx);
865 oldslots = pr->pr_slots;
866 /*
867 * We require setting slot to NULL after freeing it,
868 * this way we can check for memory leaks here.
869 */
870 KASSERT(oldslots[psrv->ps_slotno] == NULL,
871 ("Slot %d (service %s, jailid=%d) still contains data?",
872 psrv->ps_slotno, psrv->ps_name, pr->pr_id));
873 if (psrv->ps_slotno > 0) {
874 bcopy(oldslots, slots,
875 sizeof(*slots) * prison_service_slots);
876 }
877 pr->pr_slots = slots;
878 mtx_unlock(&pr->pr_mtx);
879 KASSERT(oldslots != NULL, ("oldslots == NULL"));
880 free(oldslots, M_PRISON);
881 }
882 }
883 sx_sunlock(&allprison_lock);
884 free(psrv, M_PRISON);
885}
886
887/*
888 * Function sets data for the given jail in slot assigned for the given
889 * jail service.
890 */
891void
892prison_service_data_set(struct prison_service *psrv, struct prison *pr,
893 void *data)
894{
895
896 mtx_assert(&pr->pr_mtx, MA_OWNED);
897 pr->pr_slots[psrv->ps_slotno] = data;
898}
899
900/*
901 * Function clears slots assigned for the given jail service in the given
902 * prison structure and returns current slot data.
903 */
904void *
905prison_service_data_del(struct prison_service *psrv, struct prison *pr)
906{
907 void *data;
908
909 mtx_assert(&pr->pr_mtx, MA_OWNED);
910 data = pr->pr_slots[psrv->ps_slotno];
911 pr->pr_slots[psrv->ps_slotno] = NULL;
912 return (data);
913}
914
915/*
916 * Function returns current data from the slot assigned to the given jail
917 * service for the given jail.
918 */
919void *
920prison_service_data_get(struct prison_service *psrv, struct prison *pr)
921{
922
923 mtx_assert(&pr->pr_mtx, MA_OWNED);
924 return (pr->pr_slots[psrv->ps_slotno]);
925}
926
703static int
704sysctl_jail_list(SYSCTL_HANDLER_ARGS)
705{
706 struct xprison *xp, *sxp;
707 struct prison *pr;
708 int count, error;
709
710 if (jailed(req->td->td_ucred))
711 return (0);
927static int
928sysctl_jail_list(SYSCTL_HANDLER_ARGS)
929{
930 struct xprison *xp, *sxp;
931 struct prison *pr;
932 int count, error;
933
934 if (jailed(req->td->td_ucred))
935 return (0);
712retry:
713 mtx_lock(&allprison_mtx);
714 count = prisoncount;
715 mtx_unlock(&allprison_mtx);
716
936
717 if (count == 0)
937 sx_slock(&allprison_lock);
938 if ((count = prisoncount) == 0) {
939 sx_sunlock(&allprison_lock);
718 return (0);
940 return (0);
941 }
719
720 sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
942
943 sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
721 mtx_lock(&allprison_mtx);
722 if (count != prisoncount) {
723 mtx_unlock(&allprison_mtx);
724 free(sxp, M_TEMP);
725 goto retry;
726 }
727
728 LIST_FOREACH(pr, &allprison, pr_list) {
729 mtx_lock(&pr->pr_mtx);
730 xp->pr_version = XPRISON_VERSION;
731 xp->pr_id = pr->pr_id;
732 strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
733 strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
734 xp->pr_ip = pr->pr_ip;
735 mtx_unlock(&pr->pr_mtx);
736 xp++;
737 }
944
945 LIST_FOREACH(pr, &allprison, pr_list) {
946 mtx_lock(&pr->pr_mtx);
947 xp->pr_version = XPRISON_VERSION;
948 xp->pr_id = pr->pr_id;
949 strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
950 strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
951 xp->pr_ip = pr->pr_ip;
952 mtx_unlock(&pr->pr_mtx);
953 xp++;
954 }
738 mtx_unlock(&allprison_mtx);
955 sx_sunlock(&allprison_lock);
739
740 error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
741 free(sxp, M_TEMP);
742 return (error);
743}
744
745SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
746 NULL, 0, sysctl_jail_list, "S", "List of active jails");

--- 13 unchanged lines hidden ---
956
957 error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
958 free(sxp, M_TEMP);
959 return (error);
960}
961
962SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
963 NULL, 0, sysctl_jail_list, "S", "List of active jails");

--- 13 unchanged lines hidden ---