The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_jail.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD: releng/5.1/sys/kern/kern_jail.c 126240 2004-02-25 20:03:35Z nectar $
   10  *
   11  */
   12 
   13 #include <sys/cdefs.h>
   14 __FBSDID("$FreeBSD: releng/5.1/sys/kern/kern_jail.c 126240 2004-02-25 20:03:35Z nectar $");
   15 
   16 #include <sys/param.h>
   17 #include <sys/types.h>
   18 #include <sys/kernel.h>
   19 #include <sys/systm.h>
   20 #include <sys/errno.h>
   21 #include <sys/sysproto.h>
   22 #include <sys/malloc.h>
   23 #include <sys/proc.h>
   24 #include <sys/jail.h>
   25 #include <sys/lock.h>
   26 #include <sys/mutex.h>
   27 #include <sys/namei.h>
   28 #include <sys/queue.h>
   29 #include <sys/socket.h>
   30 #include <sys/syscallsubr.h>
   31 #include <sys/sysctl.h>
   32 #include <sys/vnode.h>
   33 #include <net/if.h>
   34 #include <netinet/in.h>
   35 
   36 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
   37 
   38 SYSCTL_DECL(_security);
   39 SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
   40     "Jail rules");
   41 
   42 mp_fixme("these variables need a lock")
   43 
   44 int     jail_set_hostname_allowed = 1;
   45 SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
   46     &jail_set_hostname_allowed, 0,
   47     "Processes in jail can set their hostnames");
   48 
   49 int     jail_socket_unixiproute_only = 1;
   50 SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
   51     &jail_socket_unixiproute_only, 0,
   52     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
   53 
   54 int     jail_sysvipc_allowed = 0;
   55 SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
   56     &jail_sysvipc_allowed, 0,
   57     "Processes in jail can use System V IPC primitives");
   58 
   59 /* allprison, lastprid, and prisoncount are protected by allprison_mtx. */
   60 struct  prisonlist allprison;
   61 struct  mtx allprison_mtx;
   62 int     lastprid = 0;
   63 int     prisoncount = 0;
   64 
   65 static void              init_prison(void *);
   66 static struct prison    *prison_find(int);
   67 static int               sysctl_jail_list(SYSCTL_HANDLER_ARGS);
   68 
   69 static void
   70 init_prison(void *data __unused)
   71 {
   72 
   73         mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF);
   74         LIST_INIT(&allprison);
   75 }
   76 
   77 SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
   78 
   79 /*
   80  * MPSAFE
   81  *
   82  * struct jail_args {
   83  *      struct jail *jail;
   84  * };
   85  */
   86 int
   87 jail(struct thread *td, struct jail_args *uap)
   88 {
   89         struct nameidata nd;
   90         struct prison *pr, *tpr;
   91         struct jail j;
   92         struct jail_attach_args jaa;
   93         int error, tryprid;
   94 
   95         error = copyin(uap->jail, &j, sizeof(j));
   96         if (error)
   97                 return (error);
   98         if (j.version != 0)
   99                 return (EINVAL);
  100 
  101         MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
  102         mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
  103         pr->pr_ref = 1;
  104         error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
  105         if (error)
  106                 goto e_killmtx;
  107         mtx_lock(&Giant);
  108         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path, td);
  109         error = namei(&nd);
  110         if (error) {
  111                 mtx_unlock(&Giant);
  112                 goto e_killmtx;
  113         }
  114         pr->pr_root = nd.ni_vp;
  115         VOP_UNLOCK(nd.ni_vp, 0, td);
  116         NDFREE(&nd, NDF_ONLY_PNBUF);
  117         mtx_unlock(&Giant);
  118         error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
  119         if (error)
  120                 goto e_dropvnref;
  121         pr->pr_ip = j.ip_number;
  122         pr->pr_linux = NULL;
  123         pr->pr_securelevel = securelevel;
  124 
  125         /* Determine next pr_id and add prison to allprison list. */
  126         mtx_lock(&allprison_mtx);
  127         tryprid = lastprid + 1;
  128         if (tryprid == JAIL_MAX)
  129                 tryprid = 1;
  130 next:
  131         LIST_FOREACH(tpr, &allprison, pr_list) {
  132                 if (tpr->pr_id == tryprid) {
  133                         tryprid++;
  134                         if (tryprid == JAIL_MAX) {
  135                                 mtx_unlock(&allprison_mtx);
  136                                 error = EAGAIN;
  137                                 goto e_dropvnref;
  138                         }
  139                         goto next;
  140                 }
  141         }
  142         pr->pr_id = jaa.jid = lastprid = tryprid;
  143         LIST_INSERT_HEAD(&allprison, pr, pr_list);
  144         prisoncount++;
  145         mtx_unlock(&allprison_mtx);
  146 
  147         error = jail_attach(td, &jaa);
  148         if (error)
  149                 goto e_dropprref;
  150         mtx_lock(&pr->pr_mtx);
  151         pr->pr_ref--;
  152         mtx_unlock(&pr->pr_mtx);
  153         td->td_retval[0] = jaa.jid;
  154         return (0);
  155 e_dropprref:
  156         mtx_lock(&allprison_mtx);
  157         LIST_REMOVE(pr, pr_list);
  158         prisoncount--;
  159         mtx_unlock(&allprison_mtx);
  160 e_dropvnref:
  161         mtx_lock(&Giant);
  162         vrele(pr->pr_root);
  163         mtx_unlock(&Giant);
  164 e_killmtx:
  165         mtx_destroy(&pr->pr_mtx);
  166         FREE(pr, M_PRISON);
  167         return (error);
  168 }
  169 
  170 /*
  171  * MPSAFE
  172  *
  173  * struct jail_attach_args {
  174  *      int jid;
  175  * };
  176  */
  177 int
  178 jail_attach(struct thread *td, struct jail_attach_args *uap)
  179 {
  180         struct proc *p;
  181         struct ucred *newcred, *oldcred;
  182         struct prison *pr;
  183         int error;
  184         
  185         /*
  186          * XXX: Note that there is a slight race here if two threads
  187          * in the same privileged process attempt to attach to two
  188          * different jails at the same time.  It is important for
  189          * user processes not to do this, or they might end up with
  190          * a process root from one prison, but attached to the jail
  191          * of another.
  192          */
  193         error = suser(td);
  194         if (error)
  195                 return (error);
  196 
  197         p = td->td_proc;
  198         mtx_lock(&allprison_mtx);
  199         pr = prison_find(uap->jid);
  200         if (pr == NULL) {
  201                 mtx_unlock(&allprison_mtx);
  202                 return (EINVAL);
  203         }
  204         pr->pr_ref++;
  205         mtx_unlock(&pr->pr_mtx);
  206         mtx_unlock(&allprison_mtx);
  207 
  208         mtx_lock(&Giant);
  209         vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td);
  210         if ((error = change_dir(pr->pr_root, td)) != 0)
  211                 goto e_unlock;
  212 #ifdef MAC
  213         if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root)))
  214                 goto e_unlock;
  215 #endif
  216         VOP_UNLOCK(pr->pr_root, 0, td);
  217         change_root(pr->pr_root, td);
  218         mtx_unlock(&Giant);
  219 
  220         newcred = crget();
  221         PROC_LOCK(p);
  222         oldcred = p->p_ucred;
  223         setsugid(p);
  224         crcopy(newcred, oldcred);
  225         newcred->cr_prison = pr;
  226         p->p_ucred = newcred;
  227         PROC_UNLOCK(p);
  228         crfree(oldcred);
  229         return (0);
  230 e_unlock:
  231         VOP_UNLOCK(pr->pr_root, 0, td);
  232         mtx_unlock(&Giant);
  233         mtx_lock(&pr->pr_mtx);
  234         pr->pr_ref--;
  235         mtx_unlock(&pr->pr_mtx);
  236         return (error);
  237 }
  238 
  239 /*
  240  * Returns a locked prison instance, or NULL on failure.
  241  */
  242 static struct prison *
  243 prison_find(int prid)
  244 {
  245         struct prison *pr;
  246 
  247         mtx_assert(&allprison_mtx, MA_OWNED);
  248         LIST_FOREACH(pr, &allprison, pr_list) {
  249                 if (pr->pr_id == prid) {
  250                         mtx_lock(&pr->pr_mtx);
  251                         return (pr);
  252                 }
  253         }
  254         return (NULL);
  255 }
  256 
  257 void
  258 prison_free(struct prison *pr)
  259 {
  260 
  261         mtx_assert(&Giant, MA_OWNED);
  262         mtx_lock(&allprison_mtx);
  263         mtx_lock(&pr->pr_mtx);
  264         pr->pr_ref--;
  265         if (pr->pr_ref == 0) {
  266                 LIST_REMOVE(pr, pr_list);
  267                 mtx_unlock(&pr->pr_mtx);
  268                 prisoncount--;
  269                 mtx_unlock(&allprison_mtx);
  270                 vrele(pr->pr_root);
  271                 mtx_destroy(&pr->pr_mtx);
  272                 if (pr->pr_linux != NULL)
  273                         FREE(pr->pr_linux, M_PRISON);
  274                 FREE(pr, M_PRISON);
  275                 return;
  276         }
  277         mtx_unlock(&pr->pr_mtx);
  278         mtx_unlock(&allprison_mtx);
  279 }
  280 
  281 void
  282 prison_hold(struct prison *pr)
  283 {
  284 
  285         mtx_lock(&pr->pr_mtx);
  286         pr->pr_ref++;
  287         mtx_unlock(&pr->pr_mtx);
  288 }
  289 
  290 u_int32_t
  291 prison_getip(struct ucred *cred)
  292 {
  293 
  294         return (cred->cr_prison->pr_ip);
  295 }
  296 
  297 int
  298 prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
  299 {
  300         u_int32_t tmp;
  301 
  302         if (!jailed(cred))
  303                 return (0);
  304         if (flag) 
  305                 tmp = *ip;
  306         else
  307                 tmp = ntohl(*ip);
  308         if (tmp == INADDR_ANY) {
  309                 if (flag) 
  310                         *ip = cred->cr_prison->pr_ip;
  311                 else
  312                         *ip = htonl(cred->cr_prison->pr_ip);
  313                 return (0);
  314         }
  315         if (tmp == INADDR_LOOPBACK) {
  316                 if (flag)
  317                         *ip = cred->cr_prison->pr_ip;
  318                 else
  319                         *ip = htonl(cred->cr_prison->pr_ip);
  320                 return (0);
  321         }
  322         if (cred->cr_prison->pr_ip != tmp)
  323                 return (1);
  324         return (0);
  325 }
  326 
  327 void
  328 prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
  329 {
  330         u_int32_t tmp;
  331 
  332         if (!jailed(cred))
  333                 return;
  334         if (flag)
  335                 tmp = *ip;
  336         else
  337                 tmp = ntohl(*ip);
  338         if (tmp == INADDR_LOOPBACK) {
  339                 if (flag)
  340                         *ip = cred->cr_prison->pr_ip;
  341                 else
  342                         *ip = htonl(cred->cr_prison->pr_ip);
  343                 return;
  344         }
  345         return;
  346 }
  347 
  348 int
  349 prison_if(struct ucred *cred, struct sockaddr *sa)
  350 {
  351         struct sockaddr_in *sai;
  352         int ok;
  353 
  354         sai = (struct sockaddr_in *)sa;
  355         if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
  356                 ok = 1;
  357         else if (sai->sin_family != AF_INET)
  358                 ok = 0;
  359         else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
  360                 ok = 1;
  361         else
  362                 ok = 0;
  363         return (ok);
  364 }
  365 
  366 /*
  367  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
  368  */
  369 int
  370 prison_check(struct ucred *cred1, struct ucred *cred2)
  371 {
  372 
  373         if (jailed(cred1)) {
  374                 if (!jailed(cred2))
  375                         return (ESRCH);
  376                 if (cred2->cr_prison != cred1->cr_prison)
  377                         return (ESRCH);
  378         }
  379 
  380         return (0);
  381 }
  382 
  383 /*
  384  * Return 1 if the passed credential is in a jail, otherwise 0.
  385  */
  386 int
  387 jailed(struct ucred *cred)
  388 {
  389 
  390         return (cred->cr_prison != NULL);
  391 }
  392 
  393 /*
  394  * Return the correct hostname for the passed credential.
  395  */
  396 void
  397 getcredhostname(struct ucred *cred, char *buf, size_t size)
  398 {
  399 
  400         if (jailed(cred)) {
  401                 mtx_lock(&cred->cr_prison->pr_mtx);
  402                 strlcpy(buf, cred->cr_prison->pr_host, size);
  403                 mtx_unlock(&cred->cr_prison->pr_mtx);
  404         } else
  405                 strlcpy(buf, hostname, size);
  406 }
  407 
  408 static int
  409 sysctl_jail_list(SYSCTL_HANDLER_ARGS)
  410 {
  411         struct xprison *xp, *sxp;
  412         struct prison *pr;
  413         int count, error;
  414 
  415         mtx_assert(&Giant, MA_OWNED);
  416 retry:
  417         mtx_lock(&allprison_mtx);
  418         count = prisoncount;
  419         mtx_unlock(&allprison_mtx);
  420 
  421         if (count == 0)
  422                 return (0);
  423 
  424         sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
  425         mtx_lock(&allprison_mtx);
  426         if (count != prisoncount) {
  427                 mtx_unlock(&allprison_mtx);
  428                 free(sxp, M_TEMP);
  429                 goto retry;
  430         }
  431         
  432         LIST_FOREACH(pr, &allprison, pr_list) {
  433                 mtx_lock(&pr->pr_mtx);
  434                 xp->pr_version = XPRISON_VERSION;
  435                 xp->pr_id = pr->pr_id;
  436                 strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
  437                 strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
  438                 xp->pr_ip = pr->pr_ip;
  439                 mtx_unlock(&pr->pr_mtx);
  440                 xp++;
  441         }
  442         mtx_unlock(&allprison_mtx);
  443 
  444         error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
  445         free(sxp, M_TEMP);
  446         if (error)
  447                 return (error);
  448         return (0);
  449 }
  450 
  451 SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
  452     NULL, 0, sysctl_jail_list, "S", "List of active jails");

Cache object: f40514a5799c955b51843fedb7dc26b7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.