? compile/GENERIC ? i386/conf/REGRESSION ? i386/conf/REGRESSION_ACL Index: compat/linux/linux_mib.c =================================================================== RCS file: /home/ncvs/src/sys/compat/linux/linux_mib.c,v retrieving revision 1.10 diff -u -r1.10 linux_mib.c --- compat/linux/linux_mib.c 2001/02/21 06:39:54 1.10 +++ compat/linux/linux_mib.c 2001/04/23 16:17:42 @@ -34,17 +34,10 @@ #include #include #include -#include #include #include -struct linux_prison { - char pr_osname[LINUX_MAX_UTSNAME]; - char pr_osrelease[LINUX_MAX_UTSNAME]; - int pr_oss_version; -}; - SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, "Linux mode"); @@ -111,39 +104,10 @@ 0, 0, linux_sysctl_oss_version, "I", "Linux OSS version"); -static struct linux_prison * -get_prison(struct proc *p) -{ - register struct prison *pr; - register struct linux_prison *lpr; - - if (!jailed(p->p_ucred)) - return (NULL); - - pr = p->p_ucred->cr_prison; - - if (pr->pr_linux == NULL) { - MALLOC(lpr, struct linux_prison *, sizeof *lpr, - M_PRISON, M_WAITOK|M_ZERO); - pr->pr_linux = lpr; - } - - return (pr->pr_linux); -} - char * linux_get_osname(p) struct proc *p; { - register struct prison *pr; - register struct linux_prison *lpr; - - pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_osname[0]) - return (lpr->pr_osname); - } return (linux_osname); } @@ -153,13 +117,8 @@ struct proc *p; char *osname; { - register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) - strcpy(lpr->pr_osname, osname); - else - strcpy(linux_osname, osname); + strcpy(linux_osname, osname); return (0); } @@ -168,16 +127,7 @@ linux_get_osrelease(p) struct proc *p; { - register struct prison *pr; - register struct linux_prison *lpr; - pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_osrelease[0]) - return (lpr->pr_osrelease); - } - return (linux_osrelease); } @@ -186,13 +136,8 @@ struct proc *p; char *osrelease; { - register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) - strcpy(lpr->pr_osrelease, osrelease); - else - strcpy(linux_osrelease, osrelease); + strcpy(linux_osrelease, osrelease); return (0); } @@ -201,15 +146,6 @@ linux_get_oss_version(p) struct proc *p; { - register struct prison *pr; - register struct linux_prison *lpr; - - pr = p->p_ucred->cr_prison; - if (pr != NULL && pr->pr_linux != NULL) { - lpr = pr->pr_linux; - if (lpr->pr_oss_version) - return (lpr->pr_oss_version); - } return (linux_oss_version); } @@ -219,13 +155,8 @@ struct proc *p; int oss_version; { - register struct linux_prison *lpr; - lpr = get_prison(p); - if (lpr != NULL) - lpr->pr_oss_version = oss_version; - else - linux_oss_version = oss_version; + linux_oss_version = oss_version; return (0); } Index: kern/init_main.c =================================================================== RCS file: /home/ncvs/src/sys/kern/init_main.c,v retrieving revision 1.166 diff -u -r1.166 init_main.c --- kern/init_main.c 2001/04/11 18:50:50 1.166 +++ kern/init_main.c 2001/04/23 16:17:52 @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -327,7 +328,7 @@ p->p_ucred = crget(); p->p_ucred->cr_ngroups = 1; /* group 0 */ p->p_ucred->cr_uidinfo = uifind(0); - p->p_ucred->cr_prison = NULL; /* Don't jail it. */ + jail_crfirst(p->p_ucred); /* initialize jail support */ /* Create procsig. */ p->p_procsig = &procsig0; Index: kern/init_sysent.c =================================================================== RCS file: /home/ncvs/src/sys/kern/init_sysent.c,v retrieving revision 1.98 diff -u -r1.98 init_sysent.c --- kern/init_sysent.c 2001/04/11 20:21:36 1.98 +++ kern/init_sysent.c 2001/04/23 16:17:53 @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/kern/init_sysent.c,v 1.98 2001/04/11 20:21:36 rwatson Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp */ @@ -397,4 +397,5 @@ { AS(extattr_get_fd_args), (sy_call_t *)extattr_get_fd }, /* 372 = extattr_get_fd */ { AS(extattr_delete_fd_args), (sy_call_t *)extattr_delete_fd }, /* 373 = extattr_delete_fd */ { AS(__setugid_args), (sy_call_t *)__setugid }, /* 374 = __setugid */ + { AS(jailconf_args), (sy_call_t *)jailconf }, /* 375 = jailconf */ }; Index: kern/kern_jail.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v retrieving revision 1.10 diff -u -r1.10 kern_jail.c --- kern/kern_jail.c 2001/02/21 06:39:54 1.10 +++ kern/kern_jail.c 2001/04/23 16:17:54 @@ -1,196 +1,1054 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- +/*- + * Copyright (c) 2001 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * $FreeBSD: src/sys/kern/kern_jail.c,v 1.10 2001/02/21 06:39:54 rwatson Exp $ + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * + * $FreeBSD: $ */ +/* + * JailNG: from-scratch reimplementation of the jail(8) service devised by + * Poul-Henning Kamp and originally included in FreeBSD + * 4.0-RELEASE. Allow processes with appropriate privilege to confine + * themselves, and their descendants, to a restricted execution + * environment. They are prohibited from directly interacting with + * processes outside the environment, and by relying on a series of + * limits to superuser privilege, prevented from modifying other existing + * namespaces, such as the filesystem namespace. + */ #include -#include -#include #include -#include #include +#include #include +#include #include -#include +#include +#include #include #include -#include +#include + #include + +/* Flags for jaildesc.jd_flags field. */ +#define JAIL_FLAGS_INCREATE 0x00000001 +#define JAIL_FLAGS_INDESTROY 0x00000002 + +/* + * struct jaildescr: per-jail description structure. + * + * Locking: + * i - imutable once shared + * j - locked by jd_mtx + * l - locked by jd_list_mtx + */ +struct jaildescr { + struct mtx jd_mtx; + int jd_refcount; /* (j) */ + int jd_flags; /* (j) */ + char jd_name[JAIL_MAX_NAME]; /* (i) */ + + LIST_ENTRY(jaildescr) jd_list; /* (l) */ + + struct sysctl_ctx_list jd_sysctltree; /* (j) */ + struct sysctl_oid *jd_sysctltreetop; /* (j) */ + struct { + char jdd_hostname[MAXHOSTNAMELEN]; + int jdd_sysvipc_permitted; + int jdd_set_hostname_permitted; + int jdd_socket_ipv4_permitted; + int jdd_socket_unix_permitted; + int jdd_socket_route_permitted; + int jdd_socket_other_permitted; + u_int32_t jdd_ipv4addr; + } jd_data; /* (j) */ +}; + +static MALLOC_DEFINE(M_JAIL, "jail", "Jail structures"); + +static struct mtx jd_list_mtx; +static LIST_HEAD(, jaildescr) jaildescr_list; + +SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RD, 0, "jail parameters"); +SYSCTL_NODE(_jail, OID_AUTO, instance, CTLFLAG_RD, 0, "per-instance settings"); + +/* + * jail_init(): Initialize the jail subsystem, including appropriate + * locks and lists. + * Arguments: none + * Returns: none + * Locks: none + * Side effects: none + * References: none + * Notes: This call must be made before any other jail calls are invoked. + */ +static void +jail_init(void) +{ + + mtx_init(&jd_list_mtx, "jail list", MTX_DEF); + LIST_INIT(&jaildescr_list); +} +SYSINIT(jail, SI_SUB_PSEUDO, SI_ORDER_ANY, jail_init, NULL) + +/* + * jail_find(name): Return the jaildescr for a jail with name "name". + * Arguments: const char *name + * Returns: struct jaildescr * on success, NULL otherwise + * Locks: jd_list_mtx must be held + * Side effects: none + * References: none + * Notes: jd->jd_refcount will not be bumped on return. + */ +static struct jaildescr * +jail_find(const char *name) +{ + struct jaildescr *jd; + + mtx_assert(&jd_list_mtx, MA_OWNED); -MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); + LIST_FOREACH(jd, &jaildescr_list, jd_list) + if (!strncmp(name, jd->jd_name, JAIL_MAX_NAME)) + return (jd); + return (NULL); +} -SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0, - "Jail rules"); +/* + * jail_uniquename(jd): Replace jd's "name" with a unique name not present + * in any other reachable jails. + * Arguments: struct jaildescr *jd + * Returns: 1 on success, 0 on failure + * Locks: jd_list_mtx must be held + * Side effects: jd->jd_name will be modified on success or failure + * References: jd must be an exclusive jaildescr reference for the duration + * of the call. + * Notes: none + */ +static int +jail_uniquename(struct jaildescr *jd) +{ + struct jaildescr *jd_try; + pid_t pid_try; + int len; + + mtx_assert(&jd_list_mtx, MA_OWNED); + + /* + * Create named based on possible PID values. Because the number + * of jails cannot exceed the number of processes, there should + * always be a jail name available. However, because of cached + * credentials and possible garbage collection scenarios, it's + * possible to imagine otherwise, so reserve the possibility of + * failing. + */ + for (pid_try = 1; pid_try < PID_MAX; pid_try++) { + len = snprintf(jd->jd_name, JAIL_MAX_NAME, "%d", pid_try); + if (len >= JAIL_MAX_NAME) + panic("jail_uniquename: %%d doesn't fit into " + "JAIL_MAX_NAME"); + + /* Test for any matches. */ + jd_try = jail_find(jd->jd_name); + if (jd_try == NULL) + return (1); + } -int jail_set_hostname_allowed = 1; -SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, - &jail_set_hostname_allowed, 0, - "Processes in jail can set their hostnames"); - -int jail_socket_unixiproute_only = 1; -SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, - &jail_socket_unixiproute_only, 0, - "Processes in jail are limited to creating UNIX/IPv4/route sockets only"); - -int jail_sysvipc_allowed = 0; -SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, - &jail_sysvipc_allowed, 0, - "Processes in jail can use System V IPC primitives"); - -int -jail(p, uap) - struct proc *p; - struct jail_args /* { - syscallarg(struct jail *) jail; - } */ *uap; + /* No valid name. */ + return (0); +} + +/* + * jail_addjail(jd, name_provided): Given a partially completed jaildescr, + * add "jd" to the global jail list, + * filling in some remaining fields. + * Arguments: struct jaildescr *jd, int name_provided + * Returns: 0 on success, error number on failure + * Locks: jd_list_mtx must be held + * Side effects: jd->jd_name will be modified if name_provided==0 + * jd will be added to jd_list + * References: jd must be an exclusive jaildescr reference for the duration + * of the call. + * Notes: Guarantees that on success, jail name is unique. + */ +static int +jail_addjail(struct jaildescr *jd, int name_provided) { + struct jaildescr *jd_try; int error; - struct prison *pr; - struct jail j; - struct chroot_args ca; - - /* Implicitly fail if already in jail. */ - error = suser(p); - if (error) - return (error); - error = copyin(uap->jail, &j, sizeof j); - if (error) - return (error); - if (j.version != 0) - return (EINVAL); - MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO); - error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0); - if (error) - goto bail; - pr->pr_ip = j.ip_number; - - ca.path = j.path; - error = chroot(p, &ca); - if (error) - goto bail; - - p->p_ucred = crcopy(p->p_ucred); - p->p_ucred->cr_prison = pr; - pr->pr_ref = 1; + + mtx_assert(&jd_list_mtx, MA_OWNED); + + if (name_provided) { + jd_try = jail_find(jd->jd_name); + if (jd_try != NULL) + return (EBUSY); + } else { + error = jail_uniquename(jd); + if (error) + return (error); + } + + LIST_INSERT_HEAD(&jaildescr_list, jd, jd_list); + return (0); +} -bail: - FREE(pr, M_PRISON); - return (error); +/* + * jail_removejail(jd): Given a jaildescr, remove "jd" from the global + * jail list. + * Arguments: struct jaildescr *jd + * Returns: none + * Locks: jd_list_mtx must be held + * Side effects: jd will be removed from jd_list + * Referneces: jd must be an exclusive jaildescr reference for the duration + * of the call. + * Notes: none + */ +static void +jail_removejail(struct jaildescr *jd) +{ + + mtx_assert(&jd_list_mtx, MA_OWNED); + + LIST_REMOVE(jd, jd_list); +} + +/* + * jail_newjaildescr(): Allocate a new struct jaildescr and fill in some + * fields. + * Arguments: none + * Returns: struct jaildescr * + * Locks: none + * Side effects: none + * References: none + * Notes: initial refcount will be set to 0 + */ +static struct jaildescr * +jail_newjaildescr(void) +{ + struct jaildescr *jd; + + MALLOC(jd, struct jaildescr *, sizeof(*jd), M_JAIL, M_WAITOK|M_ZERO); + + mtx_init(&jd->jd_mtx, "jaildescr", MTX_DEF); + + jd->jd_refcount = 0; + jd->jd_flags = 0; + sysctl_ctx_init(&jd->jd_sysctltree); + + return (jd); } +/* + * jail_crfirst(cr): Initialize jail support for the root of the credential + * tree. + * Arguments: exclusive struct ucred *cr + * Returns: none + * Locks: none + * Side effects: none + * References: cr must be an exclusive credential reference for the duration + * of the call. + * Notes: Intended to be called only on cred0 during credential creation; + * will initialize such that the first credential is not in a jail. + */ void -prison_free(struct prison *pr) +jail_crfirst(struct ucred *cr) { - pr->pr_ref--; - if (pr->pr_ref == 0) { - if (pr->pr_linux != NULL) - FREE(pr->pr_linux, M_PRISON); - FREE(pr, M_PRISON); - } + cr->cr_jail = NULL; } +/* + * jail_crdup(cr1, cr2): When a credential copy is performed on "cr1", + * propagate necessary information concerning jails + * to "cr2". + * Arguments: shared struct ucred *cr1, exclusive struct ucred *cr2 + * Returns: none + * Locks: none + * Side effects: cr1->cr_jail->jd_refcount will be incremented + * References: cr1 must be a shared or exclusive credential reference for + * the durection of the call. cr2 must be an exclusive + * credential reference for the duration of the call. + * Notes: none + */ void -prison_hold(struct prison *pr) +jail_crdup(struct ucred *cr1, struct ucred *cr2) { + struct jaildescr *jd; - pr->pr_ref++; + if (cr1->cr_jail != NULL) { + jd = cr1->cr_jail; + mtx_lock(&jd->jd_mtx); + jd->jd_refcount++; + mtx_unlock(&jd->jd_mtx); + cr2->cr_jail = jd; + } else + cr2->cr_jail = NULL; } +/* + * jail_crfree(cr): Deallocate any jail state associated with the credential + * "cr". + * Arguments: exclusive struct ucred *cr + * Returns: none + * Locks: none + * Side effects: cr->cr_jail->jd_refcount will be decremented + * References: cr must be an exclusive credential reference for the + * duration of the call. + * Notes: none + */ +void +jail_crfree(struct ucred *cr) +{ + struct jaildescr *jd; + + if (cr->cr_jail != NULL) { + jd = cr->cr_jail; + + mtx_lock(&jd->jd_mtx); + jd->jd_refcount--; + mtx_unlock(&jd->jd_mtx); + + cr->cr_jail = NULL; + } +} + +/* + * jail_freejaildescr(jd): Clean up and free a struct jaildescr allocated + * using jail_newjaildescr(). + * Arguments: struct jaildescr * + * Returns: none + * Locks: none + * Side effects: jd will be freed + * References: jd must be an exclusive jaildescr reference for the duration + * of the call. + * Notes: none + */ +static void +jail_freejaildescr(struct jaildescr *jd) +{ + + mtx_destroy(&jd->jd_mtx); + FREE(jd, M_JAIL); +} + +/* + * jail_create(p, name, name_provided): Create a new jail, link it to + * the gloal list, generating a + * unique name if one is not + * provided. Return the name to + * the caller if it was generated + * internally. + * Arguments: struct proc *p, char *name, int name_provided + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: jaildescr will be allocated, linked to global list, + * sysctl's to manage the jail will be created. + * name may be modified if name_provided was 0; caller must + * assure that at least JAIL_MAX_NAME space is available in + * name if name_provided == 0 + * References: none + * Notes: To prevent the jail from being used during creation, the + * JAIL_INCREATE flag is set, which will cause other calls to + * return EBUSY. This allows the list and jail mutices to be + * released during potentially sleep()ing calls. If the reserved + * name for no-jail-present, JAIL_NOJAIL_NAME, is provided, an + * error will be returned. + */ +static int +jail_create(struct proc *p, char *name, int name_provided) +{ + struct jaildescr *jd; + int error; + + /* Don't permit use of the reserved name. */ + if (name_provided) { + if (!strncmp(name, JAIL_NOJAIL_NAME, JAIL_MAX_NAME)) + return (EINVAL); + } + + jd = jail_newjaildescr(); + + /* XXX fill in jail data fields. */ + + jd->jd_data.jdd_sysvipc_permitted = 0; + jd->jd_data.jdd_set_hostname_permitted = 1; + + jd->jd_data.jdd_socket_ipv4_permitted = 1; + jd->jd_data.jdd_socket_unix_permitted = 1; + jd->jd_data.jdd_socket_route_permitted = 1; + jd->jd_data.jdd_socket_other_permitted = 0; + + if (name_provided) + strncpy(jd->jd_name, name, JAIL_MAX_NAME); + + jd->jd_flags |= JAIL_FLAGS_INCREATE; + + mtx_lock(&jd_list_mtx); + error = jail_addjail(jd, name_provided); + mtx_unlock(&jd_list_mtx); + if (error) { + jail_freejaildescr(jd); + return (error); + } + + /* printf("jail_create(%s)\n", jd->jd_name); */ + jd->jd_sysctltreetop = SYSCTL_ADD_NODE(&jd->jd_sysctltree, + SYSCTL_STATIC_CHILDREN(_jail_instance), OID_AUTO, + jd->jd_name, CTLFLAG_RD, 0, "jail name"); + if (jd->jd_sysctltreetop == NULL) { + mtx_lock(&jd_list_mtx); + jail_removejail(jd); + mtx_unlock(&jd_list_mtx); + jail_freejaildescr(jd); + return (EBUSY); + } + + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "sysvipc_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_sysvipc_permitted, 0, "System V IPC permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "set_hostname_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_set_hostname_permitted, 0, + "sethostname() permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "socket_ipv4_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_socket_ipv4_permitted, 0, + "IPv4 sockets permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "socket_unix_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_socket_unix_permitted, 0, + "UNIX domain sockets permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "socket_route_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_socket_route_permitted, 0, + "routing sockets permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "socket_other_permitted", CTLFLAG_RW, + &jd->jd_data.jdd_socket_other_permitted, 0, + "other sockets permitted"); + SYSCTL_ADD_INT(&jd->jd_sysctltree, + SYSCTL_CHILDREN(jd->jd_sysctltreetop), OID_AUTO, + "ipv4addr", CTLFLAG_RW, + &jd->jd_data.jdd_ipv4addr, 0, + "IPv4 address"); + + /* Copy out the name for the caller. */ + strncpy(name, jd->jd_name, JAIL_MAX_NAME); + + mtx_lock(&jd->jd_mtx); + jd->jd_flags &= ~JAIL_FLAGS_INCREATE; + mtx_unlock(&jd->jd_mtx); + + return (0); +} + +/* + * jail_destroy(p, name): Destroy the jail with passed name, if it is + * not in use. + * Arguments: struct proc *p, char *name + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: jaildesc will be unlinked from the global list, + * deallocated, and its sysctl context (and associated + * sysctls) will be freed. + * References: none + * Notes: Because this call may sleep during various freeing operations, + * a flag is set on the jail while it is unlocked, JAIL_INDESTROY, + * which prevents new references from being generated or name + * collisions from occuring during the removal of the jail. + */ +static int +jail_destroy(struct proc *p, const char *name) +{ + struct jaildescr *jd; + + /* Don't permit use of the reserved name. */ + if (!strncmp(name, JAIL_NOJAIL_NAME, JAIL_MAX_NAME)) + return (EINVAL); + + mtx_lock(&jd_list_mtx); + jd = jail_find(name); + if (jd == NULL) { + mtx_unlock(&jd_list_mtx); + return (ENOENT); + } + mtx_lock(&jd->jd_mtx); + + if (jd->jd_flags & (JAIL_FLAGS_INCREATE | JAIL_FLAGS_INDESTROY)) { + mtx_unlock(&jd->jd_mtx); + mtx_unlock(&jd_list_mtx); + return (EBUSY); + } + + if (jd->jd_refcount > 0) { + mtx_unlock(&jd->jd_mtx); + mtx_unlock(&jd_list_mtx); + return (EBUSY); + } + + jd->jd_flags |= JAIL_FLAGS_INDESTROY; + jd->jd_sysctltreetop = NULL; + + mtx_unlock(&jd->jd_mtx); + mtx_unlock(&jd_list_mtx); + + sysctl_ctx_free(&jd->jd_sysctltree); + + mtx_lock(&jd_list_mtx); + + jail_removejail(jd); + + mtx_unlock(&jd_list_mtx); + + jail_freejaildescr(jd); + + return (0); +} + +/* + * jail_join(p, name): Attach the calling process to the jail named by + * name. + * Arguments: struct proc *p, char *name + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: p's ucred will be updated (replaced) to reflect jail + * pointer changes. jd->jd_refcount will be incremented. + * P_SUGID flag will be set on p to protect its resources + * from other processes in the jail, as this constitutes + * a credential downgrade. + * References: none + * Notes: To prevent attaching to jails still in creation or deletion, + * checks for the JAIL_INCREATE and JAIL_INDELETE flags are + * performed; EBUSY is returned if they are set. + */ +static int +jail_join(struct proc *p, const char *name) +{ + struct jaildescr *jd; + struct ucred *cr, *oldcr; + + /* Don't permit use of the reserved name. */ + if (!strncmp(name, JAIL_NOJAIL_NAME, JAIL_MAX_NAME)) + return (EINVAL); + + mtx_lock(&jd_list_mtx); + jd = jail_find(name); + if (jd == NULL) { + mtx_unlock(&jd_list_mtx); + return (ENOENT); + } + mtx_lock(&jd->jd_mtx); + + if (jd->jd_flags & (JAIL_FLAGS_INCREATE | JAIL_FLAGS_INDESTROY)) { + mtx_unlock(&jd->jd_mtx); + mtx_unlock(&jd_list_mtx); + return (EBUSY); + } + + jd->jd_refcount++; + + mtx_unlock(&jd->jd_mtx); + mtx_unlock(&jd_list_mtx); + + cr = crdup(p->p_ucred); + cr->cr_jail = jd; + PROC_LOCK(p); + setsugid(p); + oldcr = p->p_ucred; + p->p_ucred = cr; + PROC_UNLOCK(p); + crfree(oldcr); + + return (0); +} + int -prison_ip(struct ucred *cred, int flag, u_int32_t *ip) +jailconf(struct proc *p, struct jailconf_args *uap) { - u_int32_t tmp; + char name[JAIL_MAX_NAME]; + int error, name_provided; - if (!jailed(cred)) + if ((error = suser(p))) + return (error); + + if (name != NULL) { + error = copyinstr(SCARG(uap, name), name, JAIL_MAX_NAME, NULL); + if (error) + return (error); + name_provided = 1; + } else + name_provided = 0; + + switch (SCARG(uap, cmd)) { + case JAIL_CREATE: + error = jail_create(p, name, name_provided); + if (error) + return (error); + + if (!name_provided) { + error = copyout(name, SCARG(uap, name), + strlen(name)+1); + if (error) + return (error); + } + return (0); - if (flag) - tmp = *ip; - else - tmp = ntohl(*ip); - if (tmp == INADDR_ANY) { - if (flag) - *ip = cred->cr_prison->pr_ip; - else - *ip = htonl(cred->cr_prison->pr_ip); + + case JAIL_DESTROY: + if (!name_provided) + return (EINVAL); + return (jail_destroy(p, name)); + + case JAIL_JOIN: + if (!name_provided) + return (EINVAL); + return (jail_join(p, name)); + + default: + return (EINVAL); + } +} + +/* + * jailed(cr): Determine if the passed credential is in a jail. + * Arguments: shared or exclusive struct cred *cr + * Returns: 1 if in jail, 0 otherwise + * Locks: none + * Side effects: none + * References: cr must be a shared or exclusive credential reference for + * the duration of the call. + * Notes: none + */ +int +jailed(struct ucred *cr) +{ + + return (cr->cr_jail != NULL); +} + +/* + * jail_ucansee(cr1, cr2): Determine if passed credential cr1 "can see" + * subjects with credential cr2. + * Arguments: shared or exclusive struct cred *cr1, *cr2 + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr1 and cr2 must be shared or exclusive credential + * references for the duration of the call. + * Notes: none + */ +int +jail_ucansee(struct ucred *cr1, struct ucred *cr2) +{ + + if (cr1->cr_jail != NULL) { + if (cr2->cr_jail == NULL) + return (ESRCH); + if (cr1->cr_jail != cr2->cr_jail) + return (ESRCH); + } + + return (0); +} + +/* + * jail_ucansignal(cr1, cr2, int signam): Determine if passed credential + * cr1 "can signal" cr2 using signal + * signum. + * Arguments: shared or exclusive struct cred *cr1, *cr2, signal number + * int signum + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr1 and cr2 must be shared or exclusive credential + * references for the duration of the call. + * Notes: none + */ +int +jail_ucansignal(struct ucred *cr1, struct ucred *cr2, int signum) +{ + + return (jail_ucansee(cr1, cr2)); +} + +/* + * jail_ucansched(cr1, cr2): Determine if passed credential cr1 "can + * reschedule" cr2. + * Arguments: shared or exclusive struct cred *cr1, *cr2 + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr1 and cr2 must be shared or exclusive credential + * references for the duration of the call. + * Notes: none + */ +int +jail_ucansched(struct ucred *cr1, struct ucred *cr2) +{ + + return (jail_ucansee(cr1, cr2)); +} + +/* + * jail_ucandebug(cr1, cr2): Determine if passed credential cr1 "can debug" + * subjects with credential cr2. + * Arguments: shared or exclusive struct cred *cr1, *cr2 + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr1 and cr2 must be shared or exclusive credential + * references for the duration of the call. + * Notes: none + */ +int +jail_ucandebug(struct ucred *cr1, struct ucred *cr2) +{ + + return (jail_ucansee(cr1, cr2)); +} + +/* + * jail_ucansysvipc(cr): Determine if the passed credential cr can make use + * of System V IPC. + * Arguments: shared or exclusive struct ucred *cr + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr must be a shared or exclusive credential references for the + * duration of the call. + * Notes: none + */ +int +jail_ucansysvipc(struct ucred *cr) +{ + struct jaildescr *jd; + + jd = cr->cr_jail; + if (jd == NULL) return (0); + mtx_lock(&jd->jd_mtx); + + if (!jd->jd_data.jdd_sysvipc_permitted) { + mtx_unlock(&jd->jd_mtx); + return (ENOSYS); } - if (cred->cr_prison->pr_ip != tmp) - return (1); + + mtx_unlock(&jd->jd_mtx); return (0); } -void -prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip) +/* + * jail_ucanopenpty(cr1, cr2): Determine if the passed credential cr1 can + * open a pty originally opened by cr2. + * Arguments: shared or exclusive struct ucred *cr1, *cr2 + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr1 and cr2 must be shared or exclusive credential references + * for the duration of the call. + * Notes: none + */ +int +jail_ucanopenpty(struct ucred *cr1, struct ucred *cr2) { - u_int32_t tmp; - if (!jailed(cred)) - return; - if (flag) - tmp = *ip; - else - tmp = ntohl(*ip); - if (tmp == 0x7f000001) { - if (flag) - *ip = cred->cr_prison->pr_ip; - else - *ip = htonl(cred->cr_prison->pr_ip); - return; + if (cr1->cr_jail != NULL) { + if (cr2->cr_jail == NULL) + return (EBUSY); + if (cr1->cr_jail != cr2->cr_jail) + return (EBUSY); + } + return (0); +} + +/* + * jail_cansocreate(cr, domfamily, type): Determine if credential cr can + * create a socket of family + * domfamily and type type. + * Arguments: shared or exclusive struct ucred *cr, int domfamily, int type + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: none + * References: cr must be a shared or exclusive credential reference for the + * duration of the call. + * Notes: none + */ +int +jail_ucansocreate(struct ucred *cr, int domfamily, int type) +{ + struct jaildescr *jd; + int error = 0; + + jd = cr->cr_jail; + if (jd != NULL) { + mtx_lock(&jd->jd_mtx); + + switch (domfamily) { + case PF_LOCAL: + if (jd->jd_data.jdd_socket_unix_permitted) + error = 0; + else + error = EPROTONOSUPPORT; + break; + + case PF_INET: + if (jd->jd_data.jdd_socket_ipv4_permitted) + error = 0; + else + error = EPROTONOSUPPORT; + break; + + case PF_ROUTE: + if (jd->jd_data.jdd_socket_route_permitted) + error = 0; + else + error = EPROTONOSUPPORT; + + break; + default: + if (jd->jd_data.jdd_socket_other_permitted) + error = 0; + else + error = EPROTONOSUPPORT; + } + + mtx_unlock(&jd->jd_mtx); } - return; + + return (error); } +/* + * jail_gethostname(cr, hostname): Get the hostname for the jail associated + * with the passed credential cr. + * Arguments: shared or exclusive struct cred *cr, char *hostname + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: hostname will be updated on success. + * References: cr must be a shared or exclusive credential reference for + * the duration of the call. + * Notes: hostname buffer must be >= MAXHOSTNAMELEN in length. + */ int -prison_if(struct ucred *cred, struct sockaddr *sa) +jail_gethostname(struct ucred *cr, char *hostname) { - struct sockaddr_in *sai = (struct sockaddr_in*) sa; - int ok; + struct jaildescr *jd; - if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only) - ok = 1; - else if (sai->sin_family != AF_INET) - ok = 0; - else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr)) - ok = 1; - else - ok = 0; - return (ok); + jd = cr->cr_jail; + if (jd == NULL) + return (EINVAL); + mtx_lock(&jd->jd_mtx); + + strncpy(hostname, jd->jd_data.jdd_hostname, MAXHOSTNAMELEN); + + mtx_unlock(&jd->jd_mtx); + return (0); } /* - * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. + * jail_sethostname(cr, hostname): Set the hostname for the jail associated + * with passed credential cr to hostname. + * Arguments: shared or exclusive struct cred *cr, char *hostname + * Returns: 0 on success, error number otherwise + * Locks: none + * Side effects: jd->jd_data.jdd_hostname is updated on success. + * References: cr must be a shared or exclusive credential reference for + * the duration of the call. + * Notes: hostname must be <= MAXHOSTNAMELEN in length, including NUL. */ int -prison_check(cred1, cred2) - struct ucred *cred1, *cred2; +jail_sethostname(struct ucred *cr, const char *hostname) { + struct jaildescr *jd; - if (jailed(cred1)) { - if (!jailed(cred2)) - return (ESRCH); - if (cred2->cr_prison != cred1->cr_prison) - return (ESRCH); + jd = cr->cr_jail; + if (jd == NULL) + return (EINVAL); + mtx_lock(&jd->jd_mtx); + + if (!jd->jd_data.jdd_set_hostname_permitted) { + mtx_unlock(&jd->jd_mtx); + return (EPERM); } + strncpy(jd->jd_data.jdd_hostname, hostname, MAXHOSTNAMELEN); + + mtx_unlock(&jd->jd_mtx); return (0); } +/* + * jail_name(cr, buf, buflen, format): Print the jail name associated with + * the passed credential cr in the caller- + * provided buffer buf, of length buflen, + * using the provided format string, where + * one string (%s) is expected to be + * specified. + * Arguments: char *buf, length int buflen, char *format + * Returns: if the return value is greater than or equal to the buflen + * argument, the buffer was too short and results were truncated; + * otherwise, the length of the resulting string in buf. + * Locks: none + * Side effects: character buffer buf is modified to include the jail + * name. + * References: cr must be a shared or exclusive credential reference for + * the duration of the call. + * Notes: The return value should be interpreted and handled in the style + * of an snprintf() return value. If no jail is associated with + * the passed credential, an empty string will be substituted for + * the %s in the format string. + */ +int +jail_name(struct ucred *cr, char *buf, int buflen, char *format) +{ + struct jaildescr *jd; + + jd = cr->cr_jail; + if (jd == NULL) + return (snprintf(buf, buflen, format, JAIL_NOJAIL_NAME)); + else + return (snprintf(buf, buflen, format, jd->jd_name)); +} + /* - * Return 1 if the passed credential is in a jail, otherwise 0. + * XXX: Compatibility. */ +u_int32_t +prison_getipv4addr(struct ucred *cr) +{ + struct jaildescr *jd; + u_int32_t addr; + + jd = cr->cr_jail; + KASSERT(jd != NULL, ("prison_getip: credential not in jail")); + mtx_lock(&jd->jd_mtx); + + addr = jd->jd_data.jdd_ipv4addr; + + mtx_unlock(&jd->jd_mtx); + return (addr); +} + +int +prison_if(struct ucred *cr, struct sockaddr *sa) +{ + struct jaildescr *jd; + struct sockaddr_in *sai = (struct sockaddr_in *) sa; + u_int32_t addr; + int socket_ipv4_permitted, socket_other_permitted; + + jd = cr->cr_jail; + KASSERT(jd != NULL, ("prison_if: credential not in jail")); + mtx_lock(&jd->jd_mtx); + addr = jd->jd_data.jdd_ipv4addr; + socket_ipv4_permitted = jd->jd_data.jdd_socket_ipv4_permitted; + socket_other_permitted = jd->jd_data.jdd_socket_other_permitted; + mtx_unlock(&jd->jd_mtx); + + switch (sai->sin_family) { + case AF_INET: + if (socket_ipv4_permitted) { + if (addr == ntohl(sai->sin_addr.s_addr)) + return (0); + } + break; + + default: + if (socket_other_permitted) + return (0); + } + + return (1); +} + +int +prison_ip(struct ucred *cr, int flag, u_int32_t *ip) +{ + struct jaildescr *jd; + u_int32_t jailaddr, reqaddr; + + jd = cr->cr_jail; + if (jd == NULL) + return (0); + + mtx_lock(&jd->jd_mtx); + jailaddr = jd->jd_data.jdd_ipv4addr; + mtx_unlock(&jd->jd_mtx); + + if (flag) + reqaddr = *ip; + else + reqaddr = ntohl(*ip); + if (reqaddr == INADDR_ANY) { + if (flag) + *ip = jailaddr; + else + *ip = htonl(jailaddr); + return (0); + } + if (jailaddr != reqaddr) + return (1); + return (0); +} + +void +prison_remote_ip(struct ucred *cr, int flag, u_int32_t *ip) +{ + struct jaildescr *jd; + u_int32_t oldaddr, newaddr; + + jd = cr->cr_jail; + if (jd == NULL) + return; + + mtx_lock(&jd->jd_mtx); + newaddr = jd->jd_data.jdd_ipv4addr; + mtx_unlock(&jd->jd_mtx); + + if (flag) + oldaddr = *ip; + else + oldaddr = ntohl(*ip); + if (oldaddr == 0x7f000001) { + if (flag) + *ip = newaddr; + else + *ip = htonl(newaddr); + return; + } +} + int -jailed(cred) - struct ucred *cred; +jail(struct proc *p, struct jail_args *uap) { - return (cred->cr_prison != NULL); + return (ENOSYS); } Index: kern/kern_ktrace.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_ktrace.c,v retrieving revision 1.50 diff -u -r1.50 kern_ktrace.c --- kern/kern_ktrace.c 2001/03/28 11:52:53 1.50 +++ kern/kern_ktrace.c 2001/04/23 16:17:55 @@ -532,7 +532,7 @@ register struct pcred *caller = callp->p_cred; register struct pcred *target = targetp->p_cred; - if (prison_check(callp->p_ucred, targetp->p_ucred)) + if (jail_ucandebug(callp->p_ucred, targetp->p_ucred)) return (0); if ((caller->pc_ucred->cr_uid == target->p_ruid && target->p_ruid == target->p_svuid && Index: kern/kern_mib.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_mib.c,v retrieving revision 1.39 diff -u -r1.39 kern_mib.c --- kern/kern_mib.c 2001/02/21 06:39:54 1.39 +++ kern/kern_mib.c 2001/04/23 16:17:56 @@ -144,14 +144,22 @@ static int sysctl_hostname(SYSCTL_HANDLER_ARGS) { + char hostname_stack[MAXHOSTNAMELEN]; int error; if (jailed(req->p->p_ucred)) { - if (!jail_set_hostname_allowed && req->newptr) - return(EPERM); - error = sysctl_handle_string(oidp, - req->p->p_ucred->cr_prison->pr_host, - sizeof req->p->p_ucred->cr_prison->pr_host, req); + error = jail_gethostname(req->p->p_ucred, hostname_stack); + if (error) + return (error); + + error = sysctl_handle_string(oidp, hostname_stack, + sizeof(hostname_stack), req); + if (error) + return (error); + + if (req->newptr) + error = jail_sethostname(req->p->p_ucred, + hostname_stack); } else error = sysctl_handle_string(oidp, hostname, sizeof hostname, req); Index: kern/kern_prot.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v retrieving revision 1.86 diff -u -r1.86 kern_prot.c --- kern/kern_prot.c 2001/04/21 22:41:45 1.86 +++ kern/kern_prot.c 2001/04/23 16:17:56 @@ -1013,7 +1013,7 @@ { int error; - if ((error = prison_check(u1, u2))) + if ((error = jail_ucansee(u1, u2))) return (error); if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) { if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) @@ -1048,7 +1048,7 @@ * Jail semantics limit the scope of signalling to p2 in the same * jail as p1, if p1 is in jail. */ - if ((error = prison_check(p1->p_ucred, p2->p_ucred))) + if ((error = jail_ucansignal(p1->p_ucred, p2->p_ucred, signum))) return (error); /* @@ -1114,7 +1114,7 @@ if (p1 == p2) return (0); - if ((error = prison_check(p1->p_ucred, p2->p_ucred))) + if ((error = jail_ucansched(p1->p_ucred, p2->p_ucred))) return (error); if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) @@ -1161,7 +1161,7 @@ if (p1 == p2) return (0); - if ((error = prison_check(p1->p_ucred, p2->p_ucred))) + if ((error = jail_ucandebug(p1->p_ucred, p2->p_ucred))) return (error); /* not owned by you, has done setuid (unless you're root) */ @@ -1252,11 +1252,8 @@ */ if (cr->cr_uidinfo != NULL) uifree(cr->cr_uidinfo); - /* - * Free a prison, if any. - */ - if (jailed(cr)) - prison_free(cr->cr_prison); + /* Recover any jail state for the credential. */ + jail_crfree(cr); FREE((caddr_t)cr, M_CRED); } else { mtx_unlock(&cr->cr_mtx); @@ -1296,8 +1293,7 @@ *newcr = *cr; mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); uihold(newcr->cr_uidinfo); - if (jailed(newcr)) - prison_hold(newcr->cr_prison); + jail_crdup(cr, newcr); newcr->cr_ref = 1; return (newcr); } Index: kern/syscalls.c =================================================================== RCS file: /home/ncvs/src/sys/kern/syscalls.c,v retrieving revision 1.87 diff -u -r1.87 syscalls.c --- kern/syscalls.c 2001/04/11 20:21:36 1.87 +++ kern/syscalls.c 2001/04/23 16:17:56 @@ -2,7 +2,7 @@ * System call names. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/kern/syscalls.c,v 1.87 2001/04/11 20:21:36 rwatson Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp */ @@ -382,4 +382,5 @@ "extattr_get_fd", /* 372 = extattr_get_fd */ "extattr_delete_fd", /* 373 = extattr_delete_fd */ "__setugid", /* 374 = __setugid */ + "jailconf", /* 375 = jailconf */ }; Index: kern/syscalls.master =================================================================== RCS file: /home/ncvs/src/sys/kern/syscalls.master,v retrieving revision 1.88 diff -u -r1.88 syscalls.master --- kern/syscalls.master 2001/04/11 20:20:40 1.88 +++ kern/syscalls.master 2001/04/23 16:17:57 @@ -542,3 +542,4 @@ 373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \ const char *attrname); } 374 STD BSD { int __setugid(int flag); } +375 STD BSD { int jailconf(int cmd, char *name); } Index: kern/sysv_msg.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sysv_msg.c,v retrieving revision 1.30 diff -u -r1.30 sysv_msg.c --- kern/sysv_msg.c 2001/02/21 06:39:54 1.30 +++ kern/sysv_msg.c 2001/04/23 16:17:58 @@ -277,9 +277,11 @@ int a6; } */ *uap; { + int error; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) return (EINVAL); @@ -326,7 +328,7 @@ int msqid = uap->msqid; int cmd = uap->cmd; struct msqid_ds *user_msqptr = uap->buf; - int rval, eval; + int rval, eval, error; struct msqid_ds msqbuf; register struct msqid_ds *msqptr; @@ -334,8 +336,9 @@ printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); msqid = IPCID_TO_IX(msqid); @@ -463,7 +466,7 @@ struct proc *p; register struct msgget_args *uap; { - int msqid, eval; + int msqid, eval, error; int key = uap->key; int msgflg = uap->msgflg; struct ucred *cred = p->p_ucred; @@ -473,8 +476,9 @@ printf("msgget(0x%x, 0%o)\n", key, msgflg); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(cred); + if (error) + return (error); if (key != IPC_PRIVATE) { for (msqid = 0; msqid < msginfo.msgmni; msqid++) { @@ -578,7 +582,7 @@ void *user_msgp = uap->msgp; size_t msgsz = uap->msgsz; int msgflg = uap->msgflg; - int segs_needed, eval; + int segs_needed, eval, error; register struct msqid_ds *msqptr; register struct msg *msghdr; short next; @@ -588,8 +592,9 @@ msgflg); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); msqid = IPCID_TO_IX(msqid); @@ -907,7 +912,7 @@ size_t len; register struct msqid_ds *msqptr; register struct msg *msghdr; - int eval; + int eval, error; short next; #ifdef MSG_DEBUG_OK @@ -915,8 +920,9 @@ msgsz, msgtyp, msgflg); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); msqid = IPCID_TO_IX(msqid); Index: kern/sysv_sem.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sysv_sem.c,v retrieving revision 1.32 diff -u -r1.32 sysv_sem.c --- kern/sysv_sem.c 2001/02/21 06:39:54 1.32 +++ kern/sysv_sem.c 2001/04/23 16:17:59 @@ -254,9 +254,11 @@ int a5; } */ *uap; { + int error; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) return (EINVAL); @@ -456,7 +458,7 @@ union semun *arg = uap->arg; union semun real_arg; struct ucred *cred = p->p_ucred; - int i, rval, eval; + int i, rval, eval, error; struct semid_ds sbuf; register struct semid_ds *semaptr; @@ -464,8 +466,9 @@ printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(cred); + if (error) + return (error); semid = IPCID_TO_IX(semid); if (semid < 0 || semid >= seminfo.semmsl) @@ -617,7 +620,7 @@ struct proc *p; register struct semget_args *uap; { - int semid, eval; + int semid, eval, error; int key = uap->key; int nsems = uap->nsems; int semflg = uap->semflg; @@ -627,8 +630,9 @@ printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(cred); + if (error) + return (error); if (key != IPC_PRIVATE) { for (semid = 0; semid < seminfo.semmni; semid++) { @@ -741,15 +745,16 @@ register struct sembuf *sopptr; register struct sem *semptr; struct sem_undo *suptr = NULL; - int i, j, eval; + int i, j, eval, error; int do_wakeup, do_undos; #ifdef SEM_DEBUG printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops); #endif - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ Index: kern/sysv_shm.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sysv_shm.c,v retrieving revision 1.53 diff -u -r1.53 sysv_shm.c --- kern/sysv_shm.c 2001/02/21 06:39:55 1.53 +++ kern/sysv_shm.c 2001/04/23 16:17:59 @@ -227,10 +227,11 @@ struct shmdt_args *uap; { struct shmmap_state *shmmap_s; - int i; + int i, error; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; if (shmmap_s == NULL) @@ -266,8 +267,9 @@ vm_size_t size; int rv; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; if (shmmap_s == NULL) { @@ -360,8 +362,9 @@ struct shmid_ds *shmseg; struct oshmid_ds outbuf; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); shmseg = shm_find_segment_by_shmid(uap->shmid); if (shmseg == NULL) @@ -411,8 +414,9 @@ struct shmid_ds inbuf; struct shmid_ds *shmseg; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); shmseg = shm_find_segment_by_shmid(uap->shmid); if (shmseg == NULL) @@ -590,8 +594,9 @@ { int segnum, mode, error; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); mode = uap->shmflg & ACCESSPERMS; if (uap->key != IPC_PRIVATE) { @@ -620,9 +625,11 @@ int a4; } */ *uap; { + int error; - if (!jail_sysvipc_allowed && jailed(p->p_ucred)) - return (ENOSYS); + error = jail_ucansysvipc(p->p_ucred); + if (error) + return (error); if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) return EINVAL; Index: kern/tty_pty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_pty.c,v retrieving revision 1.85 diff -u -r1.85 tty_pty.c --- kern/tty_pty.c 2001/03/26 12:41:01 1.85 +++ kern/tty_pty.c 2001/04/23 16:18:00 @@ -53,6 +53,7 @@ #include #include #include +#include static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); @@ -117,7 +118,7 @@ u_char pt_ucntl; struct tty pt_tty; dev_t devs, devc; - struct prison *pt_prison; + struct ucred *pt_ucred; /* XXX Really should be an objlabel. */ }; #define PF_PKT 0x08 /* packet mode */ @@ -185,8 +186,8 @@ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; } else if (tp->t_state & TS_XCLUDE && suser(p)) { return (EBUSY); - } else if (pti->pt_prison != p->p_ucred->cr_prison) { - return (EBUSY); + } else if ((error = jail_ucanopenpty(p->p_ucred, pti->pt_ucred))) { + return (error); } if (tp->t_oproc) /* Ctrlr still around. */ (void)(*linesw[tp->t_line].l_modem)(tp, 1); @@ -346,7 +347,9 @@ (void)(*linesw[tp->t_line].l_modem)(tp, 1); tp->t_lflag &= ~EXTPROC; pti = dev->si_drv1; - pti->pt_prison = p->p_ucred->cr_prison; + + pti->pt_ucred = p->p_ucred; + crhold(pti->pt_ucred); pti->pt_flags = 0; pti->pt_send = 0; pti->pt_ucntl = 0; Index: kern/uipc_socket.c =================================================================== RCS file: /home/ncvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.95 diff -u -r1.95 uipc_socket.c --- kern/uipc_socket.c 2001/03/16 22:37:06 1.95 +++ kern/uipc_socket.c 2001/04/23 16:18:05 @@ -141,12 +141,9 @@ if (prp == 0 || prp->pr_usrreqs->pru_attach == 0) return (EPROTONOSUPPORT); - if (jailed(p->p_ucred) && jail_socket_unixiproute_only && - prp->pr_domain->dom_family != PF_LOCAL && - prp->pr_domain->dom_family != PF_INET && - prp->pr_domain->dom_family != PF_ROUTE) { - return (EPROTONOSUPPORT); - } + if ((error = jail_ucansocreate(p->p_ucred, + prp->pr_domain->dom_family, prp->pr_type))) + return (error); if (prp->pr_type != type) return (EPROTOTYPE); Index: miscfs/procfs/procfs_status.c =================================================================== RCS file: /home/ncvs/src/sys/miscfs/procfs/procfs_status.c,v retrieving revision 1.28 diff -u -r1.28 procfs_status.c --- miscfs/procfs/procfs_status.c 2001/03/07 03:10:20 1.28 +++ miscfs/procfs/procfs_status.c 2001/04/23 16:18:05 @@ -163,11 +163,8 @@ DOCHECK(); } - if (jailed(p->p_ucred)) - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - " %s", p->p_ucred->cr_prison->pr_host); - else - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -"); + ps += jail_name(p->p_ucred, ps, psbuf + sizeof(psbuf) - ps, + " %s"); DOCHECK(); ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n"); DOCHECK(); Index: netinet/in_pcb.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.83 diff -u -r1.83 in_pcb.c --- netinet/in_pcb.c 2001/03/16 19:36:23 1.83 +++ netinet/in_pcb.c 2001/04/23 16:18:24 @@ -499,7 +499,7 @@ cred = inp->inp_socket->so_cred; if (inp->inp_laddr.s_addr == INADDR_ANY && jailed(cred)) { bzero(&sa, sizeof (sa)); - sa.sin_addr.s_addr = htonl(cred->cr_prison->pr_ip); + sa.sin_addr.s_addr = htonl(prison_getipv4addr(cred)); sa.sin_len=sizeof (sa); sa.sin_family = AF_INET; error = in_pcbbind(inp, (struct sockaddr *)&sa, p); @@ -1008,7 +1008,7 @@ { if (!jailed(p->p_ucred)) return (0); - if (ntohl(inp->inp_laddr.s_addr) == p->p_ucred->cr_prison->pr_ip) + if (ntohl(inp->inp_laddr.s_addr) == prison_getipv4addr(p->p_ucred)) return (0); return (1); } Index: sys/jail.h =================================================================== RCS file: /home/ncvs/src/sys/sys/jail.h,v retrieving revision 1.11 diff -u -r1.11 jail.h --- sys/jail.h 2001/02/21 06:39:57 1.11 +++ sys/jail.h 2001/04/23 16:18:25 @@ -1,70 +1,78 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- +/*- + * Copyright (c) 2001 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * $FreeBSD: src/sys/sys/jail.h,v 1.11 2001/02/21 06:39:57 rwatson Exp $ + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * + * $FreeBSD: $ */ - -#ifndef _SYS_JAIL_H_ -#define _SYS_JAIL_H_ - -struct jail { - u_int32_t version; - char *path; - char *hostname; - u_int32_t ip_number; -}; -#ifndef _KERNEL +#ifndef _SYS_JAIL_H +#define _SYS_JAIL_H -int jail __P((struct jail *)); +#define JAIL_CREATE 1 +#define JAIL_DESTROY 2 +#define JAIL_JOIN 3 -#else /* _KERNEL */ - -#ifdef MALLOC_DECLARE -MALLOC_DECLARE(M_PRISON); -#endif - -/* - * This structure describes a prison. It is pointed to by all struct - * ucreds's of the inmates. pr_ref keeps track of them and is used to - * delete the struture when the last inmate is dead. - * - * XXX: Note: this structure needs a mutex to protect the reference count - * and other mutable fields (pr_host, pr_linux). - */ +#define JAIL_MAX_NAME 64 +#define JAIL_NOJAIL_NAME "NONE" /* reserved name for no jail present */ -struct prison { - int pr_ref; - char pr_host[MAXHOSTNAMELEN]; - u_int32_t pr_ip; - void *pr_linux; -}; +#ifdef _KERNEL /* - * Sysctl-set variables that determine global jail policy + * Public jail() functions intended to be consumed by the remainder of + * the kernel. */ -extern int jail_set_hostname_allowed; -extern int jail_socket_unixiproute_only; -extern int jail_sysvipc_allowed; +struct ucred; +void jail_crdup __P((struct ucred *cr1, struct ucred *cr2)); +void jail_crfirst __P((struct ucred *cr)); +void jail_crfree __P((struct ucred *cr)); +int jail_gethostname __P((struct ucred *cr, char *hostname)); +int jail_name __P((struct ucred *cr, char *buf, int buflen, char *format)); +int jail_sethostname __P((struct ucred *cr, const char *hostname)); +int jail_ucansocreate __P((struct ucred *cr, int domfamily, int type)); +int jail_ucandebug __P((struct ucred *cr1, struct ucred *cr2)); +int jail_ucanopenpty __P((struct ucred *cr1, struct ucred *cr2)); +int jail_ucansched __P((struct ucred *cr1, struct ucred *cr2)); +int jail_ucansee __P((struct ucred *cr1, struct ucred *cr2)); +int jail_ucansignal __P((struct ucred *cr1, struct ucred *cr2, + int signum)); +int jail_ucansysvipc __P((struct ucred *cr)); +int jailed __P((struct ucred *cr)); /* - * Kernel support functions for jail(). + * Compatibility from oldjail. */ -struct ucred; +struct prison; struct sockaddr; -int jailed __P((struct ucred *cred)); -int prison_check __P((struct ucred *cred1, struct ucred *cred2)); -void prison_free __P((struct prison *pr)); -void prison_hold __P((struct prison *pr)); +u_int32_t prison_getipv4addr __P((struct ucred *cr)); int prison_if __P((struct ucred *cred, struct sockaddr *sa)); int prison_ip __P((struct ucred *cred, int flag, u_int32_t *ip)); void prison_remote_ip __P((struct ucred *cred, int flags, u_int32_t *ip)); +#else /* !_KERNEL */ + +int jailconf __P((int cmd, const char *name)); + #endif /* !_KERNEL */ -#endif /* !_SYS_JAIL_H_ */ + +#endif /* !_SYS_JAIL_H */ Index: sys/syscall-hide.h =================================================================== RCS file: /home/ncvs/src/sys/sys/syscall-hide.h,v retrieving revision 1.81 diff -u -r1.81 syscall-hide.h --- sys/syscall-hide.h 2001/04/11 20:21:37 1.81 +++ sys/syscall-hide.h 2001/04/23 16:18:25 @@ -2,7 +2,7 @@ * System call hiders. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/sys/syscall-hide.h,v 1.81 2001/04/11 20:21:37 rwatson Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp */ @@ -288,3 +288,4 @@ HIDE_BSD(extattr_get_fd) HIDE_BSD(extattr_delete_fd) HIDE_BSD(__setugid) +HIDE_BSD(jailconf) Index: sys/syscall.h =================================================================== RCS file: /home/ncvs/src/sys/sys/syscall.h,v retrieving revision 1.85 diff -u -r1.85 syscall.h --- sys/syscall.h 2001/04/11 20:21:37 1.85 +++ sys/syscall.h 2001/04/23 16:18:25 @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/sys/syscall.h,v 1.85 2001/04/11 20:21:37 rwatson Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp */ @@ -295,4 +295,5 @@ #define SYS_extattr_get_fd 372 #define SYS_extattr_delete_fd 373 #define SYS___setugid 374 -#define SYS_MAXSYSCALL 375 +#define SYS_jailconf 375 +#define SYS_MAXSYSCALL 376 Index: sys/syscall.mk =================================================================== RCS file: /home/ncvs/src/sys/sys/syscall.mk,v retrieving revision 1.39 diff -u -r1.39 syscall.mk --- sys/syscall.mk 2001/04/11 20:21:37 1.39 +++ sys/syscall.mk 2001/04/23 16:18:25 @@ -1,6 +1,6 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. -# $FreeBSD: src/sys/sys/syscall.mk,v 1.39 2001/04/11 20:21:37 rwatson Exp $ +# $FreeBSD$ # created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp MIASM = \ syscall.o \ @@ -243,4 +243,5 @@ extattr_set_fd.o \ extattr_get_fd.o \ extattr_delete_fd.o \ - __setugid.o + __setugid.o \ + jailconf.o Index: sys/sysproto.h =================================================================== RCS file: /home/ncvs/src/sys/sys/sysproto.h,v retrieving revision 1.75 diff -u -r1.75 sysproto.h --- sys/sysproto.h 2001/04/11 20:21:37 1.75 +++ sys/sysproto.h 2001/04/23 16:18:27 @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/sys/sysproto.h,v 1.75 2001/04/11 20:21:37 rwatson Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.88 2001/04/11 20:20:40 rwatson Exp */ @@ -1063,6 +1063,10 @@ struct __setugid_args { int flag; char flag_[PAD_(int)]; }; +struct jailconf_args { + int cmd; char cmd_[PAD_(int)]; + char * name; char name_[PAD_(char *)]; +}; int nosys __P((struct proc *, struct nosys_args *)); void sys_exit __P((struct proc *, struct sys_exit_args *)); int fork __P((struct proc *, struct fork_args *)); @@ -1303,6 +1307,7 @@ int extattr_get_fd __P((struct proc *, struct extattr_get_fd_args *)); int extattr_delete_fd __P((struct proc *, struct extattr_delete_fd_args *)); int __setugid __P((struct proc *, struct __setugid_args *)); +int jailconf __P((struct proc *, struct jailconf_args *)); #ifdef COMPAT_43 Index: sys/ucred.h =================================================================== RCS file: /home/ncvs/src/sys/sys/ucred.h,v retrieving revision 1.22 diff -u -r1.22 ucred.h --- sys/ucred.h 2001/03/28 09:17:56 1.22 +++ sys/ucred.h 2001/04/23 16:18:27 @@ -52,7 +52,7 @@ short cr_ngroups; /* number of groups */ gid_t cr_groups[NGROUPS]; /* groups */ struct uidinfo *cr_uidinfo; /* per uid resource consumption */ - struct prison *cr_prison; /* jail(4) */ + struct jaildescr *cr_jail; /* jail(4) */ struct mtx cr_mtx; /* protect refcount */ }; #define cr_gid cr_groups[0]