kern_jail.c revision 131177
146197Sphk/* 246197Sphk * ---------------------------------------------------------------------------- 346197Sphk * "THE BEER-WARE LICENSE" (Revision 42): 446197Sphk * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 546197Sphk * can do whatever you want with this stuff. If we meet some day, and you think 646197Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 746197Sphk * ---------------------------------------------------------------------------- 846197Sphk */ 946155Sphk 10116182Sobrien#include <sys/cdefs.h> 11116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 131177 2004-06-27 09:03:22Z pjd $"); 12116182Sobrien 13131177Spjd#include "opt_mac.h" 14131177Spjd 1546155Sphk#include <sys/param.h> 1646155Sphk#include <sys/types.h> 1746155Sphk#include <sys/kernel.h> 1846155Sphk#include <sys/systm.h> 1946155Sphk#include <sys/errno.h> 2046155Sphk#include <sys/sysproto.h> 21131177Spjd#include <sys/mac.h> 2246155Sphk#include <sys/malloc.h> 2346155Sphk#include <sys/proc.h> 24124882Srwatson#include <sys/taskqueue.h> 2546155Sphk#include <sys/jail.h> 2687275Srwatson#include <sys/lock.h> 2787275Srwatson#include <sys/mutex.h> 28113275Smike#include <sys/namei.h> 29113275Smike#include <sys/queue.h> 3046155Sphk#include <sys/socket.h> 31113275Smike#include <sys/syscallsubr.h> 3257163Srwatson#include <sys/sysctl.h> 33113275Smike#include <sys/vnode.h> 3446155Sphk#include <net/if.h> 3546155Sphk#include <netinet/in.h> 3646155Sphk 3746155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 3846155Sphk 3989414SarrSYSCTL_DECL(_security); 4089414SarrSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 4157163Srwatson "Jail rules"); 4257163Srwatson 4384828Sjhbmp_fixme("these variables need a lock") 4484828Sjhb 4557163Srwatsonint jail_set_hostname_allowed = 1; 4689414SarrSYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, 4757163Srwatson &jail_set_hostname_allowed, 0, 4857163Srwatson "Processes in jail can set their hostnames"); 4957163Srwatson 5061235Srwatsonint jail_socket_unixiproute_only = 1; 5189414SarrSYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, 5261235Srwatson &jail_socket_unixiproute_only, 0, 5361235Srwatson "Processes in jail are limited to creating UNIX/IPv4/route sockets only"); 5461235Srwatson 5568024Srwatsonint jail_sysvipc_allowed = 0; 5689414SarrSYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, 5768024Srwatson &jail_sysvipc_allowed, 0, 5868024Srwatson "Processes in jail can use System V IPC primitives"); 5968024Srwatson 60125804Srwatsonint jail_getfsstatroot_only = 1; 61129462SpjdSYSCTL_INT(_security_jail, OID_AUTO, getfsstatroot_only, CTLFLAG_RW, 62125804Srwatson &jail_getfsstatroot_only, 0, 63125804Srwatson "Processes see only their root file system in getfsstat()"); 64125804Srwatson 65128664Sbmilekicint jail_allow_raw_sockets = 0; 66128664SbmilekicSYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW, 67128664Sbmilekic &jail_allow_raw_sockets, 0, 68128664Sbmilekic "Prison root can create raw sockets"); 69128664Sbmilekic 70113275Smike/* allprison, lastprid, and prisoncount are protected by allprison_mtx. */ 71113275Smikestruct prisonlist allprison; 72113275Smikestruct mtx allprison_mtx; 73113275Smikeint lastprid = 0; 74113275Smikeint prisoncount = 0; 75113275Smike 76113275Smikestatic void init_prison(void *); 77124882Srwatsonstatic void prison_complete(void *context, int pending); 78113275Smikestatic struct prison *prison_find(int); 79113275Smikestatic int sysctl_jail_list(SYSCTL_HANDLER_ARGS); 80113275Smike 81113275Smikestatic void 82113275Smikeinit_prison(void *data __unused) 83113275Smike{ 84113275Smike 85113275Smike mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF); 86113275Smike LIST_INIT(&allprison); 87113275Smike} 88113275Smike 89113275SmikeSYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL); 90113275Smike 9182710Sdillon/* 9282710Sdillon * MPSAFE 93114168Smike * 94114168Smike * struct jail_args { 95114168Smike * struct jail *jail; 96114168Smike * }; 9782710Sdillon */ 9846155Sphkint 99114168Smikejail(struct thread *td, struct jail_args *uap) 10046155Sphk{ 101113275Smike struct nameidata nd; 102113275Smike struct prison *pr, *tpr; 10346155Sphk struct jail j; 104113275Smike struct jail_attach_args jaa; 105113275Smike int error, tryprid; 10646155Sphk 107114168Smike error = copyin(uap->jail, &j, sizeof(j)); 10846155Sphk if (error) 10984828Sjhb return (error); 11084828Sjhb if (j.version != 0) 11184828Sjhb return (EINVAL); 11284828Sjhb 113114168Smike MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 11493818Sjhb mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF); 115113275Smike pr->pr_ref = 1; 116114168Smike error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0); 117113275Smike if (error) 118113275Smike goto e_killmtx; 119113275Smike mtx_lock(&Giant); 120113275Smike NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path, td); 121113275Smike error = namei(&nd); 122113275Smike if (error) { 123113275Smike mtx_unlock(&Giant); 124113275Smike goto e_killmtx; 125113275Smike } 126113275Smike pr->pr_root = nd.ni_vp; 127113275Smike VOP_UNLOCK(nd.ni_vp, 0, td); 128113275Smike NDFREE(&nd, NDF_ONLY_PNBUF); 129113275Smike mtx_unlock(&Giant); 130114168Smike error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0); 13184828Sjhb if (error) 132113275Smike goto e_dropvnref; 133113275Smike pr->pr_ip = j.ip_number; 134113275Smike pr->pr_linux = NULL; 135113275Smike pr->pr_securelevel = securelevel; 136113275Smike 137113275Smike /* Determine next pr_id and add prison to allprison list. */ 138113275Smike mtx_lock(&allprison_mtx); 139113275Smike tryprid = lastprid + 1; 140113275Smike if (tryprid == JAIL_MAX) 141113275Smike tryprid = 1; 142113275Smikenext: 143113275Smike LIST_FOREACH(tpr, &allprison, pr_list) { 144113275Smike if (tpr->pr_id == tryprid) { 145113275Smike tryprid++; 146113275Smike if (tryprid == JAIL_MAX) { 147113275Smike mtx_unlock(&allprison_mtx); 148113275Smike error = EAGAIN; 149113275Smike goto e_dropvnref; 150113275Smike } 151113275Smike goto next; 152113275Smike } 153113275Smike } 154113275Smike pr->pr_id = jaa.jid = lastprid = tryprid; 155113275Smike LIST_INSERT_HEAD(&allprison, pr, pr_list); 156113275Smike prisoncount++; 157113275Smike mtx_unlock(&allprison_mtx); 158113275Smike 159113275Smike error = jail_attach(td, &jaa); 160113275Smike if (error) 161113275Smike goto e_dropprref; 162113275Smike mtx_lock(&pr->pr_mtx); 163113275Smike pr->pr_ref--; 164113275Smike mtx_unlock(&pr->pr_mtx); 165113275Smike td->td_retval[0] = jaa.jid; 166113275Smike return (0); 167113275Smikee_dropprref: 168113275Smike mtx_lock(&allprison_mtx); 169113275Smike LIST_REMOVE(pr, pr_list); 170113275Smike prisoncount--; 171113275Smike mtx_unlock(&allprison_mtx); 172113275Smikee_dropvnref: 17399227Siedowse mtx_lock(&Giant); 174113275Smike vrele(pr->pr_root); 17599227Siedowse mtx_unlock(&Giant); 176113275Smikee_killmtx: 177113275Smike mtx_destroy(&pr->pr_mtx); 178113275Smike FREE(pr, M_PRISON); 179113275Smike return (error); 180113275Smike} 181113275Smike 182113275Smike/* 183113275Smike * MPSAFE 184114168Smike * 185114168Smike * struct jail_attach_args { 186114168Smike * int jid; 187114168Smike * }; 188113275Smike */ 189113275Smikeint 190114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 191113275Smike{ 192113275Smike struct proc *p; 193113275Smike struct ucred *newcred, *oldcred; 194113275Smike struct prison *pr; 195113275Smike int error; 196113275Smike 197126023Snectar /* 198126023Snectar * XXX: Note that there is a slight race here if two threads 199126023Snectar * in the same privileged process attempt to attach to two 200126023Snectar * different jails at the same time. It is important for 201126023Snectar * user processes not to do this, or they might end up with 202126023Snectar * a process root from one prison, but attached to the jail 203126023Snectar * of another. 204126023Snectar */ 205126023Snectar error = suser(td); 206126023Snectar if (error) 207126023Snectar return (error); 208126023Snectar 209113275Smike p = td->td_proc; 210113275Smike mtx_lock(&allprison_mtx); 211113275Smike pr = prison_find(uap->jid); 212113275Smike if (pr == NULL) { 213113275Smike mtx_unlock(&allprison_mtx); 214113275Smike return (EINVAL); 215113275Smike } 216113275Smike pr->pr_ref++; 217113275Smike mtx_unlock(&pr->pr_mtx); 218113275Smike mtx_unlock(&allprison_mtx); 219113275Smike 220113275Smike mtx_lock(&Giant); 221113275Smike vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td); 222113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 223113275Smike goto e_unlock; 224113275Smike#ifdef MAC 225113275Smike if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root))) 226113275Smike goto e_unlock; 227113275Smike#endif 228113275Smike VOP_UNLOCK(pr->pr_root, 0, td); 229113275Smike change_root(pr->pr_root, td); 230113275Smike mtx_unlock(&Giant); 231113275Smike 23284828Sjhb newcred = crget(); 23384828Sjhb PROC_LOCK(p); 23484828Sjhb oldcred = p->p_ucred; 235113275Smike setsugid(p); 23684828Sjhb crcopy(newcred, oldcred); 237113630Sjhb newcred->cr_prison = pr; 23884828Sjhb p->p_ucred = newcred; 23984828Sjhb PROC_UNLOCK(p); 24084828Sjhb crfree(oldcred); 24146155Sphk return (0); 242113275Smikee_unlock: 243113275Smike VOP_UNLOCK(pr->pr_root, 0, td); 244113275Smike mtx_unlock(&Giant); 245113275Smike mtx_lock(&pr->pr_mtx); 246113275Smike pr->pr_ref--; 247113275Smike mtx_unlock(&pr->pr_mtx); 24846155Sphk return (error); 24946155Sphk} 25046155Sphk 251113275Smike/* 252113275Smike * Returns a locked prison instance, or NULL on failure. 253113275Smike */ 254113275Smikestatic struct prison * 255113275Smikeprison_find(int prid) 256113275Smike{ 257113275Smike struct prison *pr; 258113275Smike 259113275Smike mtx_assert(&allprison_mtx, MA_OWNED); 260113275Smike LIST_FOREACH(pr, &allprison, pr_list) { 261113275Smike if (pr->pr_id == prid) { 262113275Smike mtx_lock(&pr->pr_mtx); 263113275Smike return (pr); 264113275Smike } 265113275Smike } 266113275Smike return (NULL); 267113275Smike} 268113275Smike 26972786Srwatsonvoid 27072786Srwatsonprison_free(struct prison *pr) 27172786Srwatson{ 27272786Srwatson 273113275Smike mtx_lock(&allprison_mtx); 27487275Srwatson mtx_lock(&pr->pr_mtx); 27572786Srwatson pr->pr_ref--; 27672786Srwatson if (pr->pr_ref == 0) { 277113275Smike LIST_REMOVE(pr, pr_list); 27887275Srwatson mtx_unlock(&pr->pr_mtx); 279113275Smike prisoncount--; 280113275Smike mtx_unlock(&allprison_mtx); 281124882Srwatson 282124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 283124882Srwatson taskqueue_enqueue(taskqueue_swi, &pr->pr_task); 28487275Srwatson return; 28572786Srwatson } 28687275Srwatson mtx_unlock(&pr->pr_mtx); 287113275Smike mtx_unlock(&allprison_mtx); 28872786Srwatson} 28972786Srwatson 290124882Srwatsonstatic void 291124882Srwatsonprison_complete(void *context, int pending) 292124882Srwatson{ 293124882Srwatson struct prison *pr; 294124882Srwatson 295124882Srwatson pr = (struct prison *)context; 296124882Srwatson 297124882Srwatson mtx_lock(&Giant); 298124882Srwatson vrele(pr->pr_root); 299124882Srwatson mtx_unlock(&Giant); 300124882Srwatson 301124882Srwatson mtx_destroy(&pr->pr_mtx); 302124882Srwatson if (pr->pr_linux != NULL) 303124882Srwatson FREE(pr->pr_linux, M_PRISON); 304124882Srwatson FREE(pr, M_PRISON); 305124882Srwatson} 306124882Srwatson 30772786Srwatsonvoid 30872786Srwatsonprison_hold(struct prison *pr) 30972786Srwatson{ 31072786Srwatson 31187275Srwatson mtx_lock(&pr->pr_mtx); 31272786Srwatson pr->pr_ref++; 31387275Srwatson mtx_unlock(&pr->pr_mtx); 31472786Srwatson} 31572786Srwatson 31687275Srwatsonu_int32_t 31787275Srwatsonprison_getip(struct ucred *cred) 31887275Srwatson{ 31987275Srwatson 32087275Srwatson return (cred->cr_prison->pr_ip); 32187275Srwatson} 32287275Srwatson 32346155Sphkint 32472786Srwatsonprison_ip(struct ucred *cred, int flag, u_int32_t *ip) 32546155Sphk{ 32646155Sphk u_int32_t tmp; 32746155Sphk 32872786Srwatson if (!jailed(cred)) 32946155Sphk return (0); 33046155Sphk if (flag) 33146155Sphk tmp = *ip; 33246155Sphk else 33346155Sphk tmp = ntohl(*ip); 33446155Sphk if (tmp == INADDR_ANY) { 33546155Sphk if (flag) 33672786Srwatson *ip = cred->cr_prison->pr_ip; 33746155Sphk else 33872786Srwatson *ip = htonl(cred->cr_prison->pr_ip); 33946155Sphk return (0); 34046155Sphk } 34181114Srwatson if (tmp == INADDR_LOOPBACK) { 34281114Srwatson if (flag) 34381114Srwatson *ip = cred->cr_prison->pr_ip; 34481114Srwatson else 34581114Srwatson *ip = htonl(cred->cr_prison->pr_ip); 34681114Srwatson return (0); 34781114Srwatson } 34872786Srwatson if (cred->cr_prison->pr_ip != tmp) 34946155Sphk return (1); 35046155Sphk return (0); 35146155Sphk} 35246155Sphk 35346155Sphkvoid 35472786Srwatsonprison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip) 35546155Sphk{ 35646155Sphk u_int32_t tmp; 35746155Sphk 35872786Srwatson if (!jailed(cred)) 35946155Sphk return; 36046155Sphk if (flag) 36146155Sphk tmp = *ip; 36246155Sphk else 36346155Sphk tmp = ntohl(*ip); 36481114Srwatson if (tmp == INADDR_LOOPBACK) { 36546155Sphk if (flag) 36672786Srwatson *ip = cred->cr_prison->pr_ip; 36746155Sphk else 36872786Srwatson *ip = htonl(cred->cr_prison->pr_ip); 36946155Sphk return; 37046155Sphk } 37146155Sphk return; 37246155Sphk} 37346155Sphk 37446155Sphkint 37572786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 37646155Sphk{ 377114168Smike struct sockaddr_in *sai; 37846155Sphk int ok; 37946155Sphk 380114168Smike sai = (struct sockaddr_in *)sa; 38161235Srwatson if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only) 38261235Srwatson ok = 1; 38361235Srwatson else if (sai->sin_family != AF_INET) 38446155Sphk ok = 0; 38572786Srwatson else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr)) 38646155Sphk ok = 1; 38746155Sphk else 38846155Sphk ok = 0; 38946155Sphk return (ok); 39046155Sphk} 39172786Srwatson 39272786Srwatson/* 39372786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 39472786Srwatson */ 39572786Srwatsonint 396114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 39772786Srwatson{ 39872786Srwatson 39972786Srwatson if (jailed(cred1)) { 40072786Srwatson if (!jailed(cred2)) 40172786Srwatson return (ESRCH); 40272786Srwatson if (cred2->cr_prison != cred1->cr_prison) 40372786Srwatson return (ESRCH); 40472786Srwatson } 40572786Srwatson 40672786Srwatson return (0); 40772786Srwatson} 40872786Srwatson 40972786Srwatson/* 41072786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 41172786Srwatson */ 41272786Srwatsonint 413114168Smikejailed(struct ucred *cred) 41472786Srwatson{ 41572786Srwatson 41672786Srwatson return (cred->cr_prison != NULL); 41772786Srwatson} 41891384Srobert 41991384Srobert/* 42091384Srobert * Return the correct hostname for the passed credential. 42191384Srobert */ 42291391Srobertvoid 423114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 42491384Srobert{ 42591384Srobert 42691391Srobert if (jailed(cred)) { 42791391Srobert mtx_lock(&cred->cr_prison->pr_mtx); 428105354Srobert strlcpy(buf, cred->cr_prison->pr_host, size); 42991391Srobert mtx_unlock(&cred->cr_prison->pr_mtx); 430114168Smike } else 431105354Srobert strlcpy(buf, hostname, size); 43291384Srobert} 433113275Smike 434125804Srwatson/* 435125804Srwatson * Return 1 if the passed credential can "see" the passed mountpoint 436125804Srwatson * when performing a getfsstat(); otherwise, 0. 437125804Srwatson */ 438125804Srwatsonint 439125804Srwatsonprison_check_mount(struct ucred *cred, struct mount *mp) 440125804Srwatson{ 441125804Srwatson 442125805Srwatson if (jail_getfsstatroot_only && cred->cr_prison != NULL) { 443125804Srwatson if (cred->cr_prison->pr_root->v_mount != mp) 444125804Srwatson return (0); 445125804Srwatson } 446125804Srwatson return (1); 447125804Srwatson} 448125804Srwatson 449113275Smikestatic int 450113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 451113275Smike{ 452113275Smike struct xprison *xp, *sxp; 453113275Smike struct prison *pr; 454113275Smike int count, error; 455113275Smike 456113275Smike mtx_assert(&Giant, MA_OWNED); 457127020Spjd if (jailed(req->td->td_ucred)) 458125806Srwatson return (0); 459113275Smikeretry: 460113275Smike mtx_lock(&allprison_mtx); 461113275Smike count = prisoncount; 462113275Smike mtx_unlock(&allprison_mtx); 463113275Smike 464113275Smike if (count == 0) 465113275Smike return (0); 466113275Smike 467113275Smike sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO); 468113275Smike mtx_lock(&allprison_mtx); 469113275Smike if (count != prisoncount) { 470113275Smike mtx_unlock(&allprison_mtx); 471113275Smike free(sxp, M_TEMP); 472113275Smike goto retry; 473113275Smike } 474113275Smike 475113275Smike LIST_FOREACH(pr, &allprison, pr_list) { 476113275Smike mtx_lock(&pr->pr_mtx); 477113275Smike xp->pr_version = XPRISON_VERSION; 478113275Smike xp->pr_id = pr->pr_id; 479113275Smike strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 480113275Smike strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 481113275Smike xp->pr_ip = pr->pr_ip; 482113275Smike mtx_unlock(&pr->pr_mtx); 483113275Smike xp++; 484113275Smike } 485113275Smike mtx_unlock(&allprison_mtx); 486113275Smike 487113275Smike error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count); 488113275Smike free(sxp, M_TEMP); 489113275Smike if (error) 490113275Smike return (error); 491113275Smike return (0); 492113275Smike} 493113275Smike 494113275SmikeSYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD, 495113275Smike NULL, 0, sysctl_jail_list, "S", "List of active jails"); 496126004Spjd 497126004Spjdstatic int 498126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 499126004Spjd{ 500126004Spjd int error, injail; 501126004Spjd 502126004Spjd injail = jailed(req->td->td_ucred); 503126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 504126004Spjd 505126004Spjd return (error); 506126004Spjd} 507126004SpjdSYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD, 508126004Spjd NULL, 0, sysctl_jail_jailed, "I", "Process in jail?"); 509