kern_jail.c revision 84828
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 *
950477Speter * $FreeBSD: head/sys/kern/kern_jail.c 84828 2001-10-11 23:39:43Z jhb $
1046197Sphk *
1146197Sphk */
1246155Sphk
1346155Sphk#include <sys/param.h>
1446155Sphk#include <sys/types.h>
1546155Sphk#include <sys/kernel.h>
1646155Sphk#include <sys/systm.h>
1746155Sphk#include <sys/errno.h>
1846155Sphk#include <sys/sysproto.h>
1946155Sphk#include <sys/malloc.h>
2046155Sphk#include <sys/proc.h>
2146155Sphk#include <sys/jail.h>
2246155Sphk#include <sys/socket.h>
2357163Srwatson#include <sys/sysctl.h>
2446155Sphk#include <net/if.h>
2546155Sphk#include <netinet/in.h>
2646155Sphk
2746155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
2846155Sphk
2957163SrwatsonSYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
3057163Srwatson    "Jail rules");
3157163Srwatson
3284828Sjhbmp_fixme("these variables need a lock")
3384828Sjhb
3457163Srwatsonint	jail_set_hostname_allowed = 1;
3557163SrwatsonSYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
3657163Srwatson    &jail_set_hostname_allowed, 0,
3757163Srwatson    "Processes in jail can set their hostnames");
3857163Srwatson
3961235Srwatsonint	jail_socket_unixiproute_only = 1;
4061235SrwatsonSYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
4161235Srwatson    &jail_socket_unixiproute_only, 0,
4261235Srwatson    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
4361235Srwatson
4468024Srwatsonint	jail_sysvipc_allowed = 0;
4568024SrwatsonSYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
4668024Srwatson    &jail_sysvipc_allowed, 0,
4768024Srwatson    "Processes in jail can use System V IPC primitives");
4868024Srwatson
4982710Sdillon/*
5082710Sdillon * MPSAFE
5182710Sdillon */
5246155Sphkint
5383366Sjulianjail(td, uap)
5483366Sjulian	struct thread *td;
5572786Srwatson	struct jail_args /* {
5672786Srwatson		syscallarg(struct jail *) jail;
5772786Srwatson	} */ *uap;
5846155Sphk{
5983366Sjulian	struct proc *p = td->td_proc;
6046155Sphk	int error;
6146155Sphk	struct prison *pr;
6246155Sphk	struct jail j;
6346155Sphk	struct chroot_args ca;
6484828Sjhb	struct ucred *newcred = NULL, *oldcred;
6546155Sphk
6646155Sphk	error = copyin(uap->jail, &j, sizeof j);
6746155Sphk	if (error)
6884828Sjhb		return (error);
6984828Sjhb	if (j.version != 0)
7084828Sjhb		return (EINVAL);
7184828Sjhb
7284828Sjhb	mtx_lock(&Giant);
7369781Sdwmalone	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
7483989Srwatson	pr->pr_securelevel = securelevel;
7546155Sphk	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
7684828Sjhb	if (error)
7746155Sphk		goto bail;
7846155Sphk	ca.path = j.path;
7983366Sjulian	error = chroot(td, &ca);
8046155Sphk	if (error)
8146155Sphk		goto bail;
8284828Sjhb	newcred = crget();
8384828Sjhb	pr->pr_ip = j.ip_number;
8484828Sjhb	PROC_LOCK(p);
8584828Sjhb	/* Implicitly fail if already in jail.  */
8684828Sjhb	error = suser(p);
8784828Sjhb	if (error)
8884828Sjhb		goto badcred;
8984828Sjhb	oldcred = p->p_ucred;
9084828Sjhb	crcopy(newcred, oldcred);
9184828Sjhb	p->p_ucred = newcred;
9272786Srwatson	p->p_ucred->cr_prison = pr;
9372786Srwatson	pr->pr_ref = 1;
9484828Sjhb	PROC_UNLOCK(p);
9584828Sjhb	crfree(oldcred);
9682710Sdillon	mtx_unlock(&Giant);
9746155Sphk	return (0);
9884828Sjhbbadcred:
9984828Sjhb	PROC_UNLOCK(p);
10084828Sjhb	crfree(newcred);
10146155Sphkbail:
10246155Sphk	FREE(pr, M_PRISON);
10382710Sdillon	mtx_unlock(&Giant);
10446155Sphk	return (error);
10546155Sphk}
10646155Sphk
10772786Srwatsonvoid
10872786Srwatsonprison_free(struct prison *pr)
10972786Srwatson{
11072786Srwatson
11172786Srwatson	pr->pr_ref--;
11272786Srwatson	if (pr->pr_ref == 0) {
11372786Srwatson		if (pr->pr_linux != NULL)
11472786Srwatson			FREE(pr->pr_linux, M_PRISON);
11572786Srwatson		FREE(pr, M_PRISON);
11672786Srwatson	}
11772786Srwatson}
11872786Srwatson
11972786Srwatsonvoid
12072786Srwatsonprison_hold(struct prison *pr)
12172786Srwatson{
12272786Srwatson
12372786Srwatson	pr->pr_ref++;
12472786Srwatson}
12572786Srwatson
12646155Sphkint
12772786Srwatsonprison_ip(struct ucred *cred, int flag, u_int32_t *ip)
12846155Sphk{
12946155Sphk	u_int32_t tmp;
13046155Sphk
13172786Srwatson	if (!jailed(cred))
13246155Sphk		return (0);
13346155Sphk	if (flag)
13446155Sphk		tmp = *ip;
13546155Sphk	else
13646155Sphk		tmp = ntohl(*ip);
13746155Sphk	if (tmp == INADDR_ANY) {
13846155Sphk		if (flag)
13972786Srwatson			*ip = cred->cr_prison->pr_ip;
14046155Sphk		else
14172786Srwatson			*ip = htonl(cred->cr_prison->pr_ip);
14246155Sphk		return (0);
14346155Sphk	}
14481114Srwatson	if (tmp == INADDR_LOOPBACK) {
14581114Srwatson		if (flag)
14681114Srwatson			*ip = cred->cr_prison->pr_ip;
14781114Srwatson		else
14881114Srwatson			*ip = htonl(cred->cr_prison->pr_ip);
14981114Srwatson		return (0);
15081114Srwatson	}
15172786Srwatson	if (cred->cr_prison->pr_ip != tmp)
15246155Sphk		return (1);
15346155Sphk	return (0);
15446155Sphk}
15546155Sphk
15646155Sphkvoid
15772786Srwatsonprison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
15846155Sphk{
15946155Sphk	u_int32_t tmp;
16046155Sphk
16172786Srwatson	if (!jailed(cred))
16246155Sphk		return;
16346155Sphk	if (flag)
16446155Sphk		tmp = *ip;
16546155Sphk	else
16646155Sphk		tmp = ntohl(*ip);
16781114Srwatson	if (tmp == INADDR_LOOPBACK) {
16846155Sphk		if (flag)
16972786Srwatson			*ip = cred->cr_prison->pr_ip;
17046155Sphk		else
17172786Srwatson			*ip = htonl(cred->cr_prison->pr_ip);
17246155Sphk		return;
17346155Sphk	}
17446155Sphk	return;
17546155Sphk}
17646155Sphk
17746155Sphkint
17872786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa)
17946155Sphk{
18046155Sphk	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
18146155Sphk	int ok;
18246155Sphk
18361235Srwatson	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
18461235Srwatson		ok = 1;
18561235Srwatson	else if (sai->sin_family != AF_INET)
18646155Sphk		ok = 0;
18772786Srwatson	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
18846155Sphk		ok = 1;
18946155Sphk	else
19046155Sphk		ok = 0;
19146155Sphk	return (ok);
19246155Sphk}
19372786Srwatson
19472786Srwatson/*
19572786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
19672786Srwatson */
19772786Srwatsonint
19872786Srwatsonprison_check(cred1, cred2)
19972786Srwatson	struct ucred *cred1, *cred2;
20072786Srwatson{
20172786Srwatson
20272786Srwatson	if (jailed(cred1)) {
20372786Srwatson		if (!jailed(cred2))
20472786Srwatson			return (ESRCH);
20572786Srwatson		if (cred2->cr_prison != cred1->cr_prison)
20672786Srwatson			return (ESRCH);
20772786Srwatson	}
20872786Srwatson
20972786Srwatson	return (0);
21072786Srwatson}
21172786Srwatson
21272786Srwatson/*
21372786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0.
21472786Srwatson */
21572786Srwatsonint
21672786Srwatsonjailed(cred)
21772786Srwatson	struct ucred *cred;
21872786Srwatson{
21972786Srwatson
22072786Srwatson	return (cred->cr_prison != NULL);
22172786Srwatson}
222