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 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> |
28#include <sys/sx.h> |
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 |
81/* allprison, lastprid, and prisoncount are protected by allprison_lock. */ |
82struct prisonlist allprison; |
83struct sx allprison_lock; |
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 |
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 |
111 sx_init(&allprison_lock, "allprison"); |
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; |
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 } |
166 167 /* Determine next pr_id and add prison to allprison list. */ |
168 sx_xlock(&allprison_lock); |
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) { |
177 sx_xunlock(&allprison_lock); |
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++; |
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); |
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: |
202 sx_xlock(&allprison_lock); |
203 LIST_REMOVE(pr, pr_list); 204 prisoncount--; |
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); |
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; |
246 sx_slock(&allprison_lock); |
247 pr = prison_find(uap->jid); 248 if (pr == NULL) { |
249 sx_sunlock(&allprison_lock); |
250 return (EINVAL); 251 } 252 pr->pr_ref++; 253 mtx_unlock(&pr->pr_mtx); |
254 sx_sunlock(&allprison_lock); |
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 |
295 sx_assert(&allprison_lock, SX_LOCKED); |
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; |
309 |
310 sx_xlock(&allprison_lock); |
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--; |
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); |
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); |
328 sx_xunlock(&allprison_lock); |
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 |
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); |
936 |
937 sx_slock(&allprison_lock); 938 if ((count = prisoncount) == 0) { 939 sx_sunlock(&allprison_lock); |
940 return (0); |
941 } |
942 943 sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO); |
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 } |
955 sx_sunlock(&allprison_lock); |
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 --- |