MFp4:
Bring in updated jail support from bz_jail branch. This enhances the current jail implementation to permit multiple addresses per jail. In addtion to IPv4, IPv6 is supported as well. Due to updated checks it is even possible to have jails without an IP address at all, which basically gives one a chroot with restricted process view, no networking,.. SCTP support was updated and supports IPv6 in jails as well. Cpuset support permits jails to be bound to specific processor sets after creation. Jails can have an unrestricted (no duplicate protection, etc.) name in addition to the hostname. The jail name cannot be changed from within a jail and is considered to be used for management purposes or as audit-token in the future. DDB 'show jails' command was added to aid debugging. Proper compat support permits 32bit jail binaries to be used on 64bit systems to manage jails. Also backward compatibility was preserved where possible: for jail v1 syscalls, as well as with user space management utilities. Both jail as well as prison version were updated for the new features. A gap was intentionally left as the intermediate versions had been used by various patches floating around the last years. Bump __FreeBSD_version for the afore mentioned and in kernel changes. Special thanks to: - Pawel Jakub Dawidek (pjd) for his multi-IPv4 patches and Olivier Houchard (cognet) for initial single-IPv6 patches. - Jeff Roberson (jeff) and Randall Stewart (rrs) for their help, ideas and review on cpuset and SCTP support. - Robert Watson (rwatson) for lots and lots of help, discussions, suggestions and review of most of the patch at various stages. - John Baldwin (jhb) for his help. - Simon L. Nielsen (simon) as early adopter testing changes on cluster machines as well as all the testers and people who provided feedback the last months on freebsd-jail and other channels. - My employer, CK Software GmbH, for the support so I could work on this. Reviewed by: (see above) MFC after: 3 months (this is just so that I get the mail) X-MFC Before: 7.2-RELEASE if possible
This commit is contained in:
parent
f0f4475a13
commit
413628a7e3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185435
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 29, 2008
|
||||
.Dd November 29, 2008
|
||||
.Dt CPUSET 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -46,7 +46,7 @@
|
||||
and
|
||||
.Fn cpuset_setaffinity
|
||||
allow the manipulation of sets of CPUs available to processes, threads,
|
||||
interrupts and other resources.
|
||||
interrupts, jails and other resources.
|
||||
These functions may manipulate sets of CPUs that contain many processes
|
||||
or per-object anonymous masks that effect only a single object.
|
||||
.Pp
|
||||
|
@ -8,7 +8,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 3, 2008
|
||||
.Dd November 29, 2008
|
||||
.Dt JAIL 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -32,15 +32,20 @@ The argument is a pointer to a structure describing the prison:
|
||||
.Bd -literal -offset indent
|
||||
struct jail {
|
||||
u_int32_t version;
|
||||
char *path;
|
||||
char *hostname;
|
||||
u_int32_t ip_number;
|
||||
char *path;
|
||||
char *hostname;
|
||||
char *jailname;
|
||||
unsigned int ip4s;
|
||||
unsigned int ip6s;
|
||||
struct in_addr *ip4;
|
||||
struct in6_addr *ip6;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
.Dq Li version
|
||||
defines the version of the API in use.
|
||||
It should be set to zero at this time.
|
||||
.Dv JAIL_API_VERSION
|
||||
is defined for the current version.
|
||||
.Pp
|
||||
The
|
||||
.Dq Li path
|
||||
@ -54,8 +59,24 @@ This can be changed
|
||||
from the inside of the prison.
|
||||
.Pp
|
||||
The
|
||||
.Dq Li ip_number
|
||||
can be set to the IP number assigned to the prison.
|
||||
.Dq Li jailname
|
||||
pointer is an optional name that can be assigned to the jail
|
||||
for example for managment purposes.
|
||||
.Pp
|
||||
The
|
||||
.Dq Li ip4s
|
||||
and
|
||||
.Dq Li ip6s
|
||||
give the numbers of IPv4 and IPv6 addresses that will be passed
|
||||
via their respective pointers.
|
||||
.Pp
|
||||
The
|
||||
.Dq Li ip4
|
||||
and
|
||||
.Dq Li ip6
|
||||
pointers can be set to an arrays of IPv4 and IPv6 addresses to be assigned to
|
||||
the prison, or NULL if none.
|
||||
IPv4 addresses must be in network byte order.
|
||||
.Pp
|
||||
The
|
||||
.Fn jail_attach
|
||||
|
@ -54,10 +54,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/_lock.h>
|
||||
#include <sys/_mutex.h>
|
||||
#include <sys/_task.h>
|
||||
#define _WANT_PRISON /* make jail.h give us 'struct prison' */
|
||||
#include <sys/jail.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/proc.h>
|
||||
#define _WANT_PRISON /* make jail.h give us 'struct prison' */
|
||||
#include <sys/jail.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysent.h>
|
||||
|
@ -60,7 +60,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 18, 2008
|
||||
.Dd November 29, 2008
|
||||
.Dt DDB 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -686,6 +686,15 @@ Dump the interrupt statistics.
|
||||
Show interrupt lines and their respective kernel threads.
|
||||
.\"
|
||||
.Pp
|
||||
.It Ic show Cm jails
|
||||
Show the list of
|
||||
.Xr jail 8
|
||||
instances.
|
||||
In addition to what
|
||||
.Xr jls 8
|
||||
shows, also list kernel internal details.
|
||||
.\"
|
||||
.Pp
|
||||
.It Ic show Cm lapic
|
||||
Show information from the local APIC registers for this CPU.
|
||||
.\"
|
||||
|
@ -153,6 +153,24 @@ struct stat32 {
|
||||
unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
|
||||
};
|
||||
|
||||
struct jail32_v0 {
|
||||
u_int32_t version;
|
||||
uint32_t path;
|
||||
uint32_t hostname;
|
||||
u_int32_t ip_number;
|
||||
};
|
||||
|
||||
struct jail32 {
|
||||
uint32_t version;
|
||||
uint32_t path;
|
||||
uint32_t hostname;
|
||||
uint32_t jailname;
|
||||
uint32_t ip4s;
|
||||
uint32_t ip6s;
|
||||
uint32_t ip4;
|
||||
uint32_t ip6;
|
||||
};
|
||||
|
||||
struct sigaction32 {
|
||||
u_int32_t sa_u;
|
||||
int sa_flags;
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
@ -2035,6 +2036,66 @@ freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_jail(struct thread *td, struct freebsd32_jail_args *uap)
|
||||
{
|
||||
uint32_t version;
|
||||
int error;
|
||||
struct jail j;
|
||||
|
||||
error = copyin(uap->jail, &version, sizeof(uint32_t));
|
||||
if (error)
|
||||
return (error);
|
||||
switch (version) {
|
||||
case 0:
|
||||
{
|
||||
/* FreeBSD single IPv4 jails. */
|
||||
struct jail32_v0 j32_v0;
|
||||
|
||||
bzero(&j, sizeof(struct jail));
|
||||
error = copyin(uap->jail, &j32_v0, sizeof(struct jail32_v0));
|
||||
if (error)
|
||||
return (error);
|
||||
CP(j32_v0, j, version);
|
||||
PTRIN_CP(j32_v0, j, path);
|
||||
PTRIN_CP(j32_v0, j, hostname);
|
||||
j.ip4s = j32_v0.ip_number;
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
/*
|
||||
* Version 1 was used by multi-IPv4 jail implementations
|
||||
* that never made it into the official kernel.
|
||||
*/
|
||||
return (EINVAL);
|
||||
|
||||
case 2: /* JAIL_API_VERSION */
|
||||
{
|
||||
/* FreeBSD multi-IPv4/IPv6,noIP jails. */
|
||||
struct jail32 j32;
|
||||
|
||||
error = copyin(uap->jail, &j32, sizeof(struct jail32));
|
||||
if (error)
|
||||
return (error);
|
||||
CP(j32, j, version);
|
||||
PTRIN_CP(j32, j, path);
|
||||
PTRIN_CP(j32, j, hostname);
|
||||
PTRIN_CP(j32, j, jailname);
|
||||
CP(j32, j, ip4s);
|
||||
CP(j32, j, ip6s);
|
||||
PTRIN_CP(j32, j, ip4);
|
||||
PTRIN_CP(j32, j, ip6);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* Sci-Fi jails are not supported, sorry. */
|
||||
return (EINVAL);
|
||||
}
|
||||
return (kern_jail(td, &j));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
|
||||
{
|
||||
|
@ -572,7 +572,7 @@
|
||||
off_t *sbytes, int flags); }
|
||||
337 AUE_NULL NOPROTO { int kldsym(int fileid, int cmd, \
|
||||
void *data); }
|
||||
338 AUE_JAIL NOPROTO { int jail(struct jail *jail); }
|
||||
338 AUE_JAIL STD { int freebsd32_jail(struct jail32 *jail); }
|
||||
339 AUE_NULL UNIMPL pioctl
|
||||
340 AUE_SIGPROCMASK NOPROTO { int sigprocmask(int how, \
|
||||
const sigset_t *set, sigset_t *oset); }
|
||||
|
@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/limits.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/jail.h> /* Must come after sys/proc.h */
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
@ -208,7 +209,7 @@ cpuset_rel_complete(struct cpuset *set)
|
||||
* Find a set based on an id. Returns it with a ref.
|
||||
*/
|
||||
static struct cpuset *
|
||||
cpuset_lookup(cpusetid_t setid)
|
||||
cpuset_lookup(cpusetid_t setid, struct thread *td)
|
||||
{
|
||||
struct cpuset *set;
|
||||
|
||||
@ -221,6 +222,28 @@ cpuset_lookup(cpusetid_t setid)
|
||||
if (set)
|
||||
cpuset_ref(set);
|
||||
mtx_unlock_spin(&cpuset_lock);
|
||||
|
||||
KASSERT(td != NULL, ("[%s:%d] td is NULL", __func__, __LINE__));
|
||||
if (set != NULL && jailed(td->td_ucred)) {
|
||||
struct cpuset *rset, *jset;
|
||||
struct prison *pr;
|
||||
|
||||
rset = cpuset_refroot(set);
|
||||
|
||||
pr = td->td_ucred->cr_prison;
|
||||
mtx_lock(&pr->pr_mtx);
|
||||
cpuset_ref(pr->pr_cpuset);
|
||||
jset = pr->pr_cpuset;
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
|
||||
if (jset->cs_id != rset->cs_id) {
|
||||
cpuset_rel(set);
|
||||
set = NULL;
|
||||
}
|
||||
cpuset_rel(jset);
|
||||
cpuset_rel(rset);
|
||||
}
|
||||
|
||||
return (set);
|
||||
}
|
||||
|
||||
@ -412,12 +435,38 @@ cpuset_which(cpuwhich_t which, id_t id, struct proc **pp, struct thread **tdp,
|
||||
set = cpuset_refbase(curthread->td_cpuset);
|
||||
thread_unlock(curthread);
|
||||
} else
|
||||
set = cpuset_lookup(id);
|
||||
set = cpuset_lookup(id, curthread);
|
||||
if (set) {
|
||||
*setp = set;
|
||||
return (0);
|
||||
}
|
||||
return (ESRCH);
|
||||
case CPU_WHICH_JAIL:
|
||||
{
|
||||
/* Find `set' for prison with given id. */
|
||||
struct prison *pr;
|
||||
|
||||
sx_slock(&allprison_lock);
|
||||
pr = prison_find(id);
|
||||
sx_sunlock(&allprison_lock);
|
||||
if (pr == NULL)
|
||||
return (ESRCH);
|
||||
if (jailed(curthread->td_ucred)) {
|
||||
if (curthread->td_ucred->cr_prison == pr) {
|
||||
cpuset_ref(pr->pr_cpuset);
|
||||
set = pr->pr_cpuset;
|
||||
}
|
||||
} else {
|
||||
cpuset_ref(pr->pr_cpuset);
|
||||
set = pr->pr_cpuset;
|
||||
}
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
if (set) {
|
||||
*setp = set;
|
||||
return (0);
|
||||
}
|
||||
return (ESRCH);
|
||||
}
|
||||
case CPU_WHICH_IRQ:
|
||||
return (0);
|
||||
default:
|
||||
@ -663,6 +712,59 @@ cpuset_thread0(void)
|
||||
return (set);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a cpuset, which would be cpuset_create() but
|
||||
* mark the new 'set' as root.
|
||||
*
|
||||
* We are not going to reparent the td to it. Use cpuset_reparentproc() for that.
|
||||
*
|
||||
* In case of no error, returns the set in *setp locked with a reference.
|
||||
*/
|
||||
int
|
||||
cpuset_create_root(struct thread *td, struct cpuset **setp)
|
||||
{
|
||||
struct cpuset *root;
|
||||
struct cpuset *set;
|
||||
int error;
|
||||
|
||||
KASSERT(td != NULL, ("[%s:%d] invalid td", __func__, __LINE__));
|
||||
KASSERT(setp != NULL, ("[%s:%d] invalid setp", __func__, __LINE__));
|
||||
|
||||
thread_lock(td);
|
||||
root = cpuset_refroot(td->td_cpuset);
|
||||
thread_unlock(td);
|
||||
|
||||
error = cpuset_create(setp, td->td_cpuset, &root->cs_mask);
|
||||
cpuset_rel(root);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
KASSERT(*setp != NULL, ("[%s:%d] cpuset_create returned invalid data",
|
||||
__func__, __LINE__));
|
||||
|
||||
/* Mark the set as root. */
|
||||
set = *setp;
|
||||
set->cs_flags |= CPU_SET_ROOT;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
cpuset_setproc_update_set(struct proc *p, struct cpuset *set)
|
||||
{
|
||||
int error;
|
||||
|
||||
KASSERT(p != NULL, ("[%s:%d] invalid proc", __func__, __LINE__));
|
||||
KASSERT(set != NULL, ("[%s:%d] invalid set", __func__, __LINE__));
|
||||
|
||||
cpuset_ref(set);
|
||||
error = cpuset_setproc(p->p_pid, set, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
cpuset_rel(set);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called once the final set of system cpus is known. Modifies
|
||||
* the root set and all children and mark the root readonly.
|
||||
@ -728,7 +830,7 @@ cpuset_setid(struct thread *td, struct cpuset_setid_args *uap)
|
||||
*/
|
||||
if (uap->which != CPU_WHICH_PID)
|
||||
return (EINVAL);
|
||||
set = cpuset_lookup(uap->setid);
|
||||
set = cpuset_lookup(uap->setid, td);
|
||||
if (set == NULL)
|
||||
return (ESRCH);
|
||||
error = cpuset_setproc(uap->id, set, NULL);
|
||||
@ -767,6 +869,7 @@ cpuset_getid(struct thread *td, struct cpuset_getid_args *uap)
|
||||
PROC_UNLOCK(p);
|
||||
break;
|
||||
case CPU_WHICH_CPUSET:
|
||||
case CPU_WHICH_JAIL:
|
||||
break;
|
||||
case CPU_WHICH_IRQ:
|
||||
return (EINVAL);
|
||||
@ -829,6 +932,7 @@ cpuset_getaffinity(struct thread *td, struct cpuset_getaffinity_args *uap)
|
||||
thread_unlock(ttd);
|
||||
break;
|
||||
case CPU_WHICH_CPUSET:
|
||||
case CPU_WHICH_JAIL:
|
||||
break;
|
||||
case CPU_WHICH_IRQ:
|
||||
error = EINVAL;
|
||||
@ -856,6 +960,7 @@ cpuset_getaffinity(struct thread *td, struct cpuset_getaffinity_args *uap)
|
||||
}
|
||||
break;
|
||||
case CPU_WHICH_CPUSET:
|
||||
case CPU_WHICH_JAIL:
|
||||
CPU_COPY(&set->cs_mask, mask);
|
||||
break;
|
||||
case CPU_WHICH_IRQ:
|
||||
@ -936,6 +1041,7 @@ cpuset_setaffinity(struct thread *td, struct cpuset_setaffinity_args *uap)
|
||||
PROC_UNLOCK(p);
|
||||
break;
|
||||
case CPU_WHICH_CPUSET:
|
||||
case CPU_WHICH_JAIL:
|
||||
break;
|
||||
case CPU_WHICH_IRQ:
|
||||
error = EINVAL;
|
||||
@ -958,7 +1064,8 @@ cpuset_setaffinity(struct thread *td, struct cpuset_setaffinity_args *uap)
|
||||
error = cpuset_setproc(uap->id, NULL, mask);
|
||||
break;
|
||||
case CPU_WHICH_CPUSET:
|
||||
error = cpuset_which(CPU_WHICH_CPUSET, uap->id, &p,
|
||||
case CPU_WHICH_JAIL:
|
||||
error = cpuset_which(uap->which, uap->id, &p,
|
||||
&ttd, &set);
|
||||
if (error == 0) {
|
||||
error = cpuset_modify(set, mask);
|
||||
|
@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/pioctl.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/vmmeter.h>
|
||||
@ -453,6 +454,10 @@ exit1(struct thread *td, int rv)
|
||||
p->p_xstat = rv;
|
||||
p->p_xthread = td;
|
||||
|
||||
/* In case we are jailed tell the prison that we are gone. */
|
||||
if (jailed(p->p_ucred))
|
||||
prison_proc_free(p->p_ucred->cr_prison);
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
/*
|
||||
* Tell the DTrace fasttrap provider about the exit if it
|
||||
|
@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/pioctl.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/sched.h>
|
||||
@ -452,6 +453,11 @@ fork1(td, flags, pages, procp)
|
||||
__rangeof(struct proc, p_startzero, p_endzero));
|
||||
|
||||
p2->p_ucred = crhold(td->td_ucred);
|
||||
|
||||
/* In case we are jailed tell the prison that we exist. */
|
||||
if (jailed(p2->p_ucred))
|
||||
prison_proc_hold(p2->p_ucred->cr_prison);
|
||||
|
||||
PROC_UNLOCK(p2);
|
||||
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -98,6 +98,7 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_mac.h"
|
||||
#include "opt_zero.h"
|
||||
#include "opt_compat.h"
|
||||
@ -346,6 +347,9 @@ socreate(int dom, struct socket **aso, int type, int proto,
|
||||
if (jailed(cred) && jail_socket_unixiproute_only &&
|
||||
prp->pr_domain->dom_family != PF_LOCAL &&
|
||||
prp->pr_domain->dom_family != PF_INET &&
|
||||
#ifdef INET6
|
||||
prp->pr_domain->dom_family != PF_INET6 &&
|
||||
#endif
|
||||
prp->pr_domain->dom_family != PF_ROUTE) {
|
||||
return (EPROTONOSUPPORT);
|
||||
}
|
||||
|
@ -2211,7 +2211,7 @@ ifconf(u_long cmd, caddr_t data)
|
||||
struct sockaddr *sa = ifa->ifa_addr;
|
||||
|
||||
if (jailed(curthread->td_ucred) &&
|
||||
prison_if(curthread->td_ucred, sa))
|
||||
!prison_if(curthread->td_ucred, sa))
|
||||
continue;
|
||||
addrs++;
|
||||
#ifdef COMPAT_43
|
||||
|
160
sys/net/rtsock.c
160
sys/net/rtsock.c
@ -31,11 +31,13 @@
|
||||
*/
|
||||
#include "opt_sctp.h"
|
||||
#include "opt_mpath.h"
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/priv.h>
|
||||
@ -54,6 +56,9 @@
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/scope6_var.h>
|
||||
#endif
|
||||
|
||||
#ifdef SCTP
|
||||
extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
|
||||
@ -309,6 +314,136 @@ static struct pr_usrreqs route_usrreqs = {
|
||||
.pru_close = rts_close,
|
||||
};
|
||||
|
||||
#ifndef _SOCKADDR_UNION_DEFINED
|
||||
#define _SOCKADDR_UNION_DEFINED
|
||||
/*
|
||||
* The union of all possible address formats we handle.
|
||||
*/
|
||||
union sockaddr_union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
#endif /* _SOCKADDR_UNION_DEFINED */
|
||||
|
||||
static int
|
||||
rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp,
|
||||
struct rtentry *rt, union sockaddr_union *saun, struct ucred *cred)
|
||||
{
|
||||
|
||||
switch (info->rti_info[RTAX_DST]->sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
{
|
||||
struct in_addr ia;
|
||||
|
||||
/*
|
||||
* 1. Check if the returned address is part of the jail.
|
||||
*/
|
||||
ia = ((struct sockaddr_in *)rt->rt_ifa->ifa_addr)->sin_addr;
|
||||
if (prison_check_ip4(cred, &ia) != 0) {
|
||||
info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
||||
|
||||
} else {
|
||||
struct ifaddr *ifa;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
/*
|
||||
* 2. Try to find an address on the given outgoing
|
||||
* interface that belongs to the jail.
|
||||
*/
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
struct sockaddr *sa;
|
||||
sa = ifa->ifa_addr;
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
ia = ((struct sockaddr_in *)sa)->sin_addr;
|
||||
if (prison_check_ip4(cred, &ia) != 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
/*
|
||||
* 3. As a last resort return the 'default'
|
||||
* jail address.
|
||||
*/
|
||||
if (prison_getip4(cred, &ia) != 0)
|
||||
return (ESRCH);
|
||||
}
|
||||
bzero(&saun->sin, sizeof(struct sockaddr_in));
|
||||
saun->sin.sin_len = sizeof(struct sockaddr_in);
|
||||
saun->sin.sin_family = AF_INET;
|
||||
saun->sin.sin_addr.s_addr = ia.s_addr;
|
||||
info->rti_info[RTAX_IFA] =
|
||||
(struct sockaddr *)&saun->sin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct in6_addr ia6;
|
||||
|
||||
/*
|
||||
* 1. Check if the returned address is part of the jail.
|
||||
*/
|
||||
bcopy(&((struct sockaddr_in6 *)rt->rt_ifa->ifa_addr)->sin6_addr,
|
||||
&ia6, sizeof(struct in6_addr));
|
||||
if (prison_check_ip6(cred, &ia6) != 0) {
|
||||
info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
||||
} else {
|
||||
struct ifaddr *ifa;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
/*
|
||||
* 2. Try to find an address on the given outgoing
|
||||
* interface that belongs to the jail.
|
||||
*/
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
struct sockaddr *sa;
|
||||
sa = ifa->ifa_addr;
|
||||
if (sa->sa_family != AF_INET6)
|
||||
continue;
|
||||
bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
|
||||
&ia6, sizeof(struct in6_addr));
|
||||
if (prison_check_ip6(cred, &ia6) != 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
/*
|
||||
* 3. As a last resort return the 'default'
|
||||
* jail address.
|
||||
*/
|
||||
if (prison_getip6(cred, &ia6) != 0)
|
||||
return (ESRCH);
|
||||
}
|
||||
bzero(&saun->sin6, sizeof(struct sockaddr_in6));
|
||||
saun->sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
saun->sin6.sin6_family = AF_INET6;
|
||||
bcopy(&ia6, &saun->sin6.sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
if (sa6_recoverscope(&saun->sin6) != 0)
|
||||
return (ESRCH);
|
||||
info->rti_info[RTAX_IFA] =
|
||||
(struct sockaddr *)&saun->sin6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return (ESRCH);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
route_output(struct mbuf *m, struct socket *so)
|
||||
@ -321,7 +456,7 @@ route_output(struct mbuf *m, struct socket *so)
|
||||
struct rt_addrinfo info;
|
||||
int len, error = 0;
|
||||
struct ifnet *ifp = NULL;
|
||||
struct sockaddr_in jail;
|
||||
union sockaddr_union saun;
|
||||
|
||||
#define senderr(e) { error = e; goto flush;}
|
||||
if (m == NULL || ((m->m_len < sizeof(long)) &&
|
||||
@ -481,16 +616,17 @@ route_output(struct mbuf *m, struct socket *so)
|
||||
info.rti_info[RTAX_IFP] =
|
||||
ifp->if_addr->ifa_addr;
|
||||
if (jailed(so->so_cred)) {
|
||||
bzero(&jail, sizeof(jail));
|
||||
jail.sin_family = PF_INET;
|
||||
jail.sin_len = sizeof(jail);
|
||||
jail.sin_addr.s_addr =
|
||||
htonl(prison_getip(so->so_cred));
|
||||
info.rti_info[RTAX_IFA] =
|
||||
(struct sockaddr *)&jail;
|
||||
} else
|
||||
error = rtm_get_jailed(
|
||||
&info, ifp, rt, &saun,
|
||||
so->so_cred);
|
||||
if (error != 0) {
|
||||
RT_UNLOCK(rt);
|
||||
senderr(ESRCH);
|
||||
}
|
||||
} else {
|
||||
info.rti_info[RTAX_IFA] =
|
||||
rt->rt_ifa->ifa_addr;
|
||||
}
|
||||
if (ifp->if_flags & IFF_POINTOPOINT)
|
||||
info.rti_info[RTAX_BRD] =
|
||||
rt->rt_ifa->ifa_dstaddr;
|
||||
@ -1171,7 +1307,7 @@ sysctl_iflist(int af, struct walkarg *w)
|
||||
if (af && af != ifa->ifa_addr->sa_family)
|
||||
continue;
|
||||
if (jailed(curthread->td_ucred) &&
|
||||
prison_if(curthread->td_ucred, ifa->ifa_addr))
|
||||
!prison_if(curthread->td_ucred, ifa->ifa_addr))
|
||||
continue;
|
||||
info.rti_info[RTAX_IFA] = ifa->ifa_addr;
|
||||
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
|
||||
@ -1220,7 +1356,7 @@ sysctl_ifmalist(int af, struct walkarg *w)
|
||||
if (af && af != ifma->ifma_addr->sa_family)
|
||||
continue;
|
||||
if (jailed(curproc->p_ucred) &&
|
||||
prison_if(curproc->p_ucred, ifma->ifma_addr))
|
||||
!prison_if(curproc->p_ucred, ifma->ifma_addr))
|
||||
continue;
|
||||
info.rti_info[RTAX_IFA] = ifma->ifma_addr;
|
||||
info.rti_info[RTAX_GATEWAY] =
|
||||
|
@ -294,7 +294,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
struct in_addr laddr;
|
||||
u_short lport = 0;
|
||||
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
|
||||
int error, prison = 0;
|
||||
int error;
|
||||
int dorandom;
|
||||
|
||||
/*
|
||||
@ -323,9 +323,8 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
if (sin->sin_family != AF_INET)
|
||||
return (EAFNOSUPPORT);
|
||||
#endif
|
||||
if (sin->sin_addr.s_addr != INADDR_ANY)
|
||||
if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
|
||||
return(EINVAL);
|
||||
if (prison_local_ip4(cred, &sin->sin_addr))
|
||||
return (EINVAL);
|
||||
if (sin->sin_port != *lportp) {
|
||||
/* Don't allow the port to change. */
|
||||
if (*lportp != 0)
|
||||
@ -360,14 +359,11 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT,
|
||||
0))
|
||||
return (EACCES);
|
||||
if (jailed(cred))
|
||||
prison = 1;
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
|
||||
priv_check_cred(inp->inp_cred,
|
||||
PRIV_NETINET_REUSEPORT, 0) != 0) {
|
||||
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
|
||||
lport, prison ? 0 : INPLOOKUP_WILDCARD,
|
||||
cred);
|
||||
lport, INPLOOKUP_WILDCARD, cred);
|
||||
/*
|
||||
* XXX
|
||||
* This entire block sorely needs a rewrite.
|
||||
@ -384,10 +380,10 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
t->inp_cred->cr_uid))
|
||||
return (EADDRINUSE);
|
||||
}
|
||||
if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr))
|
||||
if (prison_local_ip4(cred, &sin->sin_addr))
|
||||
return (EADDRNOTAVAIL);
|
||||
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
|
||||
lport, prison ? 0 : wild, cred);
|
||||
lport, wild, cred);
|
||||
if (t && (t->inp_vflag & INP_TIMEWAIT)) {
|
||||
/*
|
||||
* XXXRW: If an incpb has had its timewait
|
||||
@ -419,9 +415,8 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
u_short first, last, aux;
|
||||
int count;
|
||||
|
||||
if (laddr.s_addr != INADDR_ANY)
|
||||
if (prison_ip(cred, 0, &laddr.s_addr))
|
||||
return (EINVAL);
|
||||
if (prison_local_ip4(cred, &laddr))
|
||||
return (EINVAL);
|
||||
|
||||
if (inp->inp_flags & INP_HIGHPORT) {
|
||||
first = V_ipport_hifirstauto; /* sysctl */
|
||||
@ -487,7 +482,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
} while (in_pcblookup_local(pcbinfo, laddr,
|
||||
lport, wild, cred));
|
||||
}
|
||||
if (prison_ip(cred, 0, &laddr.s_addr))
|
||||
if (prison_local_ip4(cred, &laddr))
|
||||
return (EINVAL);
|
||||
*laddrp = laddr.s_addr;
|
||||
*lportp = lport;
|
||||
@ -556,7 +551,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
struct route sro;
|
||||
int error;
|
||||
|
||||
KASSERT(laddr != NULL, ("%s: null laddr", __func__));
|
||||
KASSERT(laddr != NULL, ("%s: laddr NULL", __func__));
|
||||
|
||||
error = 0;
|
||||
ia = NULL;
|
||||
@ -608,7 +603,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
|
||||
if (prison_check_ip4(cred, &sin->sin_addr)) {
|
||||
ia = (struct in_ifaddr *)ifa;
|
||||
break;
|
||||
}
|
||||
@ -619,7 +614,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
}
|
||||
|
||||
/* 3. As a last resort return the 'default' jail address. */
|
||||
laddr->s_addr = htonl(prison_getip(cred));
|
||||
if (prison_getip4(cred, laddr) != 0)
|
||||
error = EADDRNOTAVAIL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -644,7 +640,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
/* Jailed. */
|
||||
/* 1. Check if the iface address belongs to the jail. */
|
||||
sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr;
|
||||
if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
|
||||
if (prison_check_ip4(cred, &sin->sin_addr)) {
|
||||
ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa;
|
||||
laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
|
||||
goto done;
|
||||
@ -660,7 +656,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (htonl(prison_getip(cred)) == sin->sin_addr.s_addr) {
|
||||
if (prison_check_ip4(cred, &sin->sin_addr)) {
|
||||
ia = (struct in_ifaddr *)ifa;
|
||||
break;
|
||||
}
|
||||
@ -671,7 +667,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
}
|
||||
|
||||
/* 3. As a last resort return the 'default' jail address. */
|
||||
laddr->s_addr = htonl(prison_getip(cred));
|
||||
if (prison_getip4(cred, laddr) != 0)
|
||||
error = EADDRNOTAVAIL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -717,8 +714,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (htonl(prison_getip(cred)) ==
|
||||
sin->sin_addr.s_addr) {
|
||||
if (prison_check_ip4(cred, &sin->sin_addr)) {
|
||||
ia = (struct in_ifaddr *)ifa;
|
||||
break;
|
||||
}
|
||||
@ -730,7 +726,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
}
|
||||
|
||||
/* 3. As a last resort return the 'default' jail address. */
|
||||
laddr->s_addr = htonl(prison_getip(cred));
|
||||
if (prison_getip4(cred, laddr) != 0)
|
||||
error = EADDRNOTAVAIL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -764,7 +761,7 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)nam;
|
||||
struct in_ifaddr *ia;
|
||||
struct inpcb *oinp;
|
||||
struct in_addr laddr, faddr;
|
||||
struct in_addr laddr, faddr, jailia;
|
||||
u_short lport, fport;
|
||||
int error;
|
||||
|
||||
@ -796,9 +793,17 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
|
||||
* and the primary interface supports broadcast,
|
||||
* choose the broadcast address for that interface.
|
||||
*/
|
||||
if (faddr.s_addr == INADDR_ANY)
|
||||
faddr = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr;
|
||||
else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
|
||||
if (faddr.s_addr == INADDR_ANY) {
|
||||
if (cred != NULL && jailed(cred)) {
|
||||
if (prison_getip4(cred, &jailia) != 0)
|
||||
return (EADDRNOTAVAIL);
|
||||
faddr.s_addr = jailia.s_addr;
|
||||
} else {
|
||||
faddr =
|
||||
IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->
|
||||
sin_addr;
|
||||
}
|
||||
} else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
|
||||
(TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags &
|
||||
IFF_BROADCAST))
|
||||
faddr = satosin(&TAILQ_FIRST(
|
||||
@ -1115,6 +1120,7 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV4) == 0)
|
||||
continue;
|
||||
#endif
|
||||
@ -1122,9 +1128,11 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
inp->inp_laddr.s_addr == laddr.s_addr &&
|
||||
inp->inp_lport == lport) {
|
||||
/*
|
||||
* Found.
|
||||
* Found?
|
||||
*/
|
||||
return (inp);
|
||||
if (cred == NULL ||
|
||||
inp->inp_cred->cr_prison == cred->cr_prison)
|
||||
return (inp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -1154,7 +1162,11 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
*/
|
||||
LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
|
||||
wildcard = 0;
|
||||
if (cred != NULL &&
|
||||
inp->inp_cred->cr_prison != cred->cr_prison)
|
||||
continue;
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV4) == 0)
|
||||
continue;
|
||||
/*
|
||||
@ -1187,9 +1199,8 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
if (wildcard < matchwild) {
|
||||
match = inp;
|
||||
matchwild = wildcard;
|
||||
if (matchwild == 0) {
|
||||
if (matchwild == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1207,7 +1218,7 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
struct ifnet *ifp)
|
||||
{
|
||||
struct inpcbhead *head;
|
||||
struct inpcb *inp;
|
||||
struct inpcb *inp, *tmpinp;
|
||||
u_short fport = fport_arg, lport = lport_arg;
|
||||
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
@ -1215,59 +1226,108 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
/*
|
||||
* First look for an exact match.
|
||||
*/
|
||||
tmpinp = NULL;
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV4) == 0)
|
||||
continue;
|
||||
#endif
|
||||
if (inp->inp_faddr.s_addr == faddr.s_addr &&
|
||||
inp->inp_laddr.s_addr == laddr.s_addr &&
|
||||
inp->inp_fport == fport &&
|
||||
inp->inp_lport == lport)
|
||||
return (inp);
|
||||
inp->inp_lport == lport) {
|
||||
/*
|
||||
* XXX We should be able to directly return
|
||||
* the inp here, without any checks.
|
||||
* Well unless both bound with SO_REUSEPORT?
|
||||
*/
|
||||
if (jailed(inp->inp_cred))
|
||||
return (inp);
|
||||
if (tmpinp == NULL)
|
||||
tmpinp = inp;
|
||||
}
|
||||
}
|
||||
if (tmpinp != NULL)
|
||||
return (tmpinp);
|
||||
|
||||
/*
|
||||
* Then look for a wildcard match, if requested.
|
||||
*/
|
||||
if (wildcard) {
|
||||
struct inpcb *local_wild = NULL;
|
||||
if (wildcard == INPLOOKUP_WILDCARD) {
|
||||
struct inpcb *local_wild = NULL, *local_exact = NULL;
|
||||
#ifdef INET6
|
||||
struct inpcb *local_wild_mapped = NULL;
|
||||
#endif
|
||||
struct inpcb *jail_wild = NULL;
|
||||
int injail;
|
||||
|
||||
/*
|
||||
* Order of socket selection - we always prefer jails.
|
||||
* 1. jailed, non-wild.
|
||||
* 2. jailed, wild.
|
||||
* 3. non-jailed, non-wild.
|
||||
* 4. non-jailed, wild.
|
||||
*/
|
||||
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV4) == 0)
|
||||
continue;
|
||||
#endif
|
||||
if (inp->inp_faddr.s_addr == INADDR_ANY &&
|
||||
inp->inp_lport == lport) {
|
||||
if (ifp && ifp->if_type == IFT_FAITH &&
|
||||
(inp->inp_flags & INP_FAITH) == 0)
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY ||
|
||||
inp->inp_lport != lport)
|
||||
continue;
|
||||
|
||||
/* XXX inp locking */
|
||||
if (ifp && ifp->if_type == IFT_FAITH &&
|
||||
(inp->inp_flags & INP_FAITH) == 0)
|
||||
continue;
|
||||
|
||||
injail = jailed(inp->inp_cred);
|
||||
if (injail) {
|
||||
if (!prison_check_ip4(inp->inp_cred, &laddr))
|
||||
continue;
|
||||
} else {
|
||||
if (local_exact != NULL)
|
||||
continue;
|
||||
if (inp->inp_laddr.s_addr == laddr.s_addr)
|
||||
return (inp);
|
||||
else if (inp->inp_laddr.s_addr == INADDR_ANY) {
|
||||
#ifdef INET6
|
||||
if (inp->inp_vflag & INP_IPV6PROTO)
|
||||
local_wild_mapped = inp;
|
||||
else
|
||||
#endif
|
||||
local_wild = inp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inp->inp_laddr.s_addr == laddr.s_addr) {
|
||||
if (injail)
|
||||
return (inp);
|
||||
else
|
||||
local_exact = inp;
|
||||
} else if (inp->inp_laddr.s_addr == INADDR_ANY) {
|
||||
#ifdef INET6
|
||||
if (local_wild == NULL)
|
||||
/* XXX inp locking, NULL check */
|
||||
if (inp->inp_vflag & INP_IPV6PROTO)
|
||||
local_wild_mapped = inp;
|
||||
else
|
||||
#endif /* INET6 */
|
||||
if (injail)
|
||||
jail_wild = inp;
|
||||
else
|
||||
local_wild = inp;
|
||||
}
|
||||
} /* LIST_FOREACH */
|
||||
if (jail_wild != NULL)
|
||||
return (jail_wild);
|
||||
if (local_exact != NULL)
|
||||
return (local_exact);
|
||||
if (local_wild != NULL)
|
||||
return (local_wild);
|
||||
#ifdef INET6
|
||||
if (local_wild_mapped != NULL)
|
||||
return (local_wild_mapped);
|
||||
#endif
|
||||
return (local_wild);
|
||||
}
|
||||
#endif /* defined(INET6) */
|
||||
} /* if (wildcard == INPLOOKUP_WILDCARD) */
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
@ -273,10 +273,9 @@ rip_input(struct mbuf *m, int off)
|
||||
continue;
|
||||
if (inp->inp_faddr.s_addr != ip->ip_src.s_addr)
|
||||
continue;
|
||||
if (jailed(inp->inp_cred) &&
|
||||
(htonl(prison_getip(inp->inp_cred)) !=
|
||||
ip->ip_dst.s_addr)) {
|
||||
continue;
|
||||
if (jailed(inp->inp_cred)) {
|
||||
if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst))
|
||||
continue;
|
||||
}
|
||||
if (last) {
|
||||
struct mbuf *n;
|
||||
@ -304,10 +303,9 @@ rip_input(struct mbuf *m, int off)
|
||||
if (inp->inp_faddr.s_addr &&
|
||||
inp->inp_faddr.s_addr != ip->ip_src.s_addr)
|
||||
continue;
|
||||
if (jailed(inp->inp_cred) &&
|
||||
(htonl(prison_getip(inp->inp_cred)) !=
|
||||
ip->ip_dst.s_addr)) {
|
||||
continue;
|
||||
if (jailed(inp->inp_cred)) {
|
||||
if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst))
|
||||
continue;
|
||||
}
|
||||
if (last) {
|
||||
struct mbuf *n;
|
||||
@ -369,11 +367,15 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst)
|
||||
ip->ip_off = 0;
|
||||
ip->ip_p = inp->inp_ip_p;
|
||||
ip->ip_len = m->m_pkthdr.len;
|
||||
if (jailed(inp->inp_cred))
|
||||
ip->ip_src.s_addr =
|
||||
htonl(prison_getip(inp->inp_cred));
|
||||
else
|
||||
if (jailed(inp->inp_cred)) {
|
||||
if (prison_getip4(inp->inp_cred, &ip->ip_src)) {
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
return (EPERM);
|
||||
}
|
||||
} else {
|
||||
ip->ip_src = inp->inp_laddr;
|
||||
}
|
||||
ip->ip_dst.s_addr = dst;
|
||||
ip->ip_ttl = inp->inp_ip_ttl;
|
||||
} else {
|
||||
@ -383,13 +385,10 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst)
|
||||
}
|
||||
INP_RLOCK(inp);
|
||||
ip = mtod(m, struct ip *);
|
||||
if (jailed(inp->inp_cred)) {
|
||||
if (ip->ip_src.s_addr !=
|
||||
htonl(prison_getip(inp->inp_cred))) {
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
return (EPERM);
|
||||
}
|
||||
if (!prison_check_ip4(inp->inp_cred, &ip->ip_src)) {
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -805,13 +804,8 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
if (nam->sa_len != sizeof(*addr))
|
||||
return (EINVAL);
|
||||
|
||||
if (jailed(td->td_ucred)) {
|
||||
if (addr->sin_addr.s_addr == INADDR_ANY)
|
||||
addr->sin_addr.s_addr =
|
||||
htonl(prison_getip(td->td_ucred));
|
||||
if (htonl(prison_getip(td->td_ucred)) != addr->sin_addr.s_addr)
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
if (!prison_check_ip4(td->td_ucred, &addr->sin_addr))
|
||||
return (EADDRNOTAVAIL);
|
||||
|
||||
if (TAILQ_EMPTY(&V_ifnet) ||
|
||||
(addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) ||
|
||||
|
@ -2553,7 +2553,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
struct inpcb *ip_inp;
|
||||
int port_reuse_active = 0;
|
||||
int bindall;
|
||||
int prison = 0;
|
||||
uint16_t lport;
|
||||
int error;
|
||||
uint32_t vrf_id;
|
||||
@ -2580,9 +2579,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
if (p == NULL)
|
||||
panic("null proc/thread");
|
||||
#endif
|
||||
if (p && jailed(p->td_ucred)) {
|
||||
prison = 1;
|
||||
}
|
||||
if (addr != NULL) {
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
@ -2600,18 +2596,13 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
}
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
lport = sin->sin_port;
|
||||
if (prison) {
|
||||
/*
|
||||
* For INADDR_ANY and LOOPBACK the
|
||||
* prison_ip() call will transmute
|
||||
* the ip address to the proper
|
||||
* value (i.e. the IP address owned
|
||||
* by the jail).
|
||||
*/
|
||||
if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
/*
|
||||
* For LOOPBACK the prison_local_ip4() call will transmute the ip address
|
||||
* to the proper value.
|
||||
*/
|
||||
if (p && prison_local_ip4(p->td_ucred, &sin->sin_addr) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
if (sin->sin_addr.s_addr != INADDR_ANY) {
|
||||
bindall = 0;
|
||||
@ -2634,12 +2625,16 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
return (EINVAL);
|
||||
}
|
||||
lport = sin6->sin6_port;
|
||||
|
||||
/*
|
||||
* Jail checks for IPv6 should go HERE! i.e.
|
||||
* add the prison_ip() equivilant in this
|
||||
* postion to transmute the addresses to the
|
||||
* proper one jailed.
|
||||
* For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address
|
||||
* to the proper value.
|
||||
*/
|
||||
if (p && prison_local_ip6(p->td_ucred, &sin6->sin6_addr,
|
||||
(SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
|
||||
bindall = 0;
|
||||
/* KAME hack: embed scopeid */
|
||||
|
@ -507,11 +507,10 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
|
||||
struct inpcb *ip_inp;
|
||||
int error;
|
||||
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
|
||||
|
||||
#ifdef IPSEC
|
||||
uint32_t flags;
|
||||
|
||||
#endif
|
||||
|
||||
inp = (struct sctp_inpcb *)so->so_pcb;
|
||||
if (inp != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
@ -3951,12 +3950,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
struct sctp_getaddresses *addrs;
|
||||
size_t sz;
|
||||
struct thread *td;
|
||||
int prison = 0;
|
||||
|
||||
td = (struct thread *)p;
|
||||
if (jailed(td->td_ucred)) {
|
||||
prison = 1;
|
||||
}
|
||||
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
|
||||
optsize);
|
||||
if (addrs->addr->sa_family == AF_INET) {
|
||||
@ -3966,10 +3961,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
|
||||
if (td != NULL && prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr))) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
} else if (addrs->addr->sa_family == AF_INET6) {
|
||||
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
|
||||
if (optsize < sz) {
|
||||
@ -3977,7 +3974,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
/* JAIL XXXX Add else here for V6 */
|
||||
if (td != NULL && prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
|
||||
(SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
sctp_bindx_add_address(so, inp, addrs->addr,
|
||||
addrs->sget_assoc_id, vrf_id,
|
||||
@ -3989,12 +3995,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
struct sctp_getaddresses *addrs;
|
||||
size_t sz;
|
||||
struct thread *td;
|
||||
int prison = 0;
|
||||
|
||||
td = (struct thread *)p;
|
||||
if (jailed(td->td_ucred)) {
|
||||
prison = 1;
|
||||
}
|
||||
|
||||
SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
|
||||
if (addrs->addr->sa_family == AF_INET) {
|
||||
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
|
||||
@ -4003,10 +4006,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) {
|
||||
if (td != NULL && prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr))) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
} else if (addrs->addr->sa_family == AF_INET6) {
|
||||
sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
|
||||
if (optsize < sz) {
|
||||
@ -4014,7 +4019,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
/* JAIL XXXX Add else here for V6 */
|
||||
if (td != NULL && prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
|
||||
(SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL);
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
sctp_bindx_delete_address(so, inp, addrs->addr,
|
||||
addrs->sget_assoc_id, vrf_id,
|
||||
@ -4106,13 +4120,34 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
#ifdef INET6
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6p;
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
sin6p = (struct sockaddr_in6 *)addr;
|
||||
if (p != NULL && prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sinp;
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
sinp = (struct sockaddr_in *)addr;
|
||||
if (p != NULL && prison_remote_ip4(p->td_ucred, &sinp->sin_addr) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
|
||||
return (EAFNOSUPPORT);
|
||||
}
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
SCTP_ASOC_CREATE_LOCK(inp);
|
||||
|
@ -440,8 +440,8 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
if (sinp->sin_family == AF_INET
|
||||
&& IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
|
||||
return (EAFNOSUPPORT);
|
||||
if (jailed(td->td_ucred))
|
||||
prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
|
||||
if (prison_remote_ip4(td->td_ucred, &sinp->sin_addr) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
@ -507,6 +507,10 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
in6_sin6_2_sin(&sin, sin6p);
|
||||
inp->inp_vflag |= INP_IPV4;
|
||||
inp->inp_vflag &= ~INP_IPV6;
|
||||
if (prison_remote_ip4(td->td_ucred, &sin.sin_addr) != 0) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0)
|
||||
goto out;
|
||||
error = tcp_output_connect(so, nam);
|
||||
@ -515,6 +519,10 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
inp->inp_vflag &= ~INP_IPV4;
|
||||
inp->inp_vflag |= INP_IPV6;
|
||||
inp->inp_inc.inc_isipv6 = 1;
|
||||
if (prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr) != 0) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if ((error = tcp6_connect(tp, nam, td)) != 0)
|
||||
goto out;
|
||||
error = tcp_output_connect(so, nam);
|
||||
|
@ -940,9 +940,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
* Jail may rewrite the destination address, so let it do
|
||||
* that before we use it.
|
||||
*/
|
||||
if (jailed(td->td_ucred))
|
||||
prison_remote_ip(td->td_ucred, 0,
|
||||
&sin->sin_addr.s_addr);
|
||||
if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) {
|
||||
error = EINVAL;
|
||||
goto release;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a local address or port hasn't yet been selected, or if
|
||||
@ -1194,8 +1195,11 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
return (EISCONN);
|
||||
}
|
||||
sin = (struct sockaddr_in *)nam;
|
||||
if (jailed(td->td_ucred))
|
||||
prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
|
||||
if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&udbinfo);
|
||||
return (EAFNOSUPPORT);
|
||||
}
|
||||
error = in_pcbconnect(inp, nam, td->td_ucred);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
|
@ -143,6 +143,10 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0)
|
||||
return(error);
|
||||
|
||||
if (prison_local_ip6(cred, &sin6->sin6_addr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
lport = sin6->sin6_port;
|
||||
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
|
||||
/*
|
||||
@ -217,6 +221,9 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
return (EADDRINUSE);
|
||||
}
|
||||
}
|
||||
if (prison_local_ip6(cred, &sin6->sin6_addr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
|
||||
return (EADDRNOTAVAIL);
|
||||
t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
|
||||
lport, wild, cred);
|
||||
if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT) ?
|
||||
@ -249,6 +256,9 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
}
|
||||
inp->in6p_laddr = sin6->sin6_addr;
|
||||
}
|
||||
if (prison_local_ip6(cred, &inp->in6p_laddr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
|
||||
return (EINVAL);
|
||||
if (lport == 0) {
|
||||
int e;
|
||||
if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, cred)) != 0)
|
||||
@ -308,6 +318,8 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
|
||||
sin6->sin6_addr = in6addr_loopback;
|
||||
}
|
||||
if (prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr) != 0)
|
||||
return (EADDRNOTAVAIL);
|
||||
|
||||
/*
|
||||
* XXX: in6_selectsrc might replace the bound local address
|
||||
@ -649,15 +661,16 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
|
||||
IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
|
||||
inp->inp_lport == lport) {
|
||||
/*
|
||||
* Found.
|
||||
*/
|
||||
return (inp);
|
||||
/* Found. */
|
||||
if (cred == NULL ||
|
||||
inp->inp_cred->cr_prison == cred->cr_prison)
|
||||
return (inp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -687,6 +700,10 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
*/
|
||||
LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
|
||||
wildcard = 0;
|
||||
if (cred != NULL &&
|
||||
inp->inp_cred->cr_prison != cred->cr_prison)
|
||||
continue;
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
|
||||
@ -696,7 +713,7 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(laddr))
|
||||
wildcard++;
|
||||
else if (!IN6_ARE_ADDR_EQUAL(
|
||||
&inp->in6p_laddr, laddr))
|
||||
&inp->in6p_laddr, laddr))
|
||||
continue;
|
||||
} else {
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(laddr))
|
||||
@ -705,9 +722,8 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
if (wildcard < matchwild) {
|
||||
match = inp;
|
||||
matchwild = wildcard;
|
||||
if (matchwild == 0) {
|
||||
if (matchwild == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -790,11 +806,11 @@ in6_rtchange(struct inpcb *inp, int errno)
|
||||
*/
|
||||
struct inpcb *
|
||||
in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
u_int fport_arg, struct in6_addr *laddr, u_int lport_arg,
|
||||
int wildcard, struct ifnet *ifp)
|
||||
u_int fport_arg, struct in6_addr *laddr, u_int lport_arg, int wildcard,
|
||||
struct ifnet *ifp)
|
||||
{
|
||||
struct inpcbhead *head;
|
||||
register struct inpcb *inp;
|
||||
struct inpcb *inp, *tmpinp;
|
||||
u_short fport = fport_arg, lport = lport_arg;
|
||||
int faith;
|
||||
|
||||
@ -808,10 +824,12 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
/*
|
||||
* First look for an exact match.
|
||||
*/
|
||||
tmpinp = NULL;
|
||||
head = &pcbinfo->ipi_hashbase[
|
||||
INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
|
||||
@ -819,32 +837,79 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
inp->inp_fport == fport &&
|
||||
inp->inp_lport == lport) {
|
||||
/*
|
||||
* Found.
|
||||
* XXX We should be able to directly return
|
||||
* the inp here, without any checks.
|
||||
* Well unless both bound with SO_REUSEPORT?
|
||||
*/
|
||||
return (inp);
|
||||
if (jailed(inp->inp_cred))
|
||||
return (inp);
|
||||
if (tmpinp == NULL)
|
||||
tmpinp = inp;
|
||||
}
|
||||
}
|
||||
if (wildcard) {
|
||||
struct inpcb *local_wild = NULL;
|
||||
if (tmpinp != NULL)
|
||||
return (tmpinp);
|
||||
|
||||
/*
|
||||
* Then look for a wildcard match, if requested.
|
||||
*/
|
||||
if (wildcard == INPLOOKUP_WILDCARD) {
|
||||
struct inpcb *local_wild = NULL, *local_exact = NULL;
|
||||
struct inpcb *jail_wild = NULL;
|
||||
int injail;
|
||||
|
||||
/*
|
||||
* Order of socket selection - we always prefer jails.
|
||||
* 1. jailed, non-wild.
|
||||
* 2. jailed, wild.
|
||||
* 3. non-jailed, non-wild.
|
||||
* 4. non-jailed, wild.
|
||||
*/
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
|
||||
inp->inp_lport == lport) {
|
||||
if (faith && (inp->inp_flags & INP_FAITH) == 0)
|
||||
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
|
||||
inp->inp_lport != lport) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXX inp locking */
|
||||
if (faith && (inp->inp_flags & INP_FAITH) == 0)
|
||||
continue;
|
||||
|
||||
injail = jailed(inp->inp_cred);
|
||||
if (injail) {
|
||||
if (!prison_check_ip6(inp->inp_cred, laddr))
|
||||
continue;
|
||||
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
|
||||
laddr))
|
||||
} else {
|
||||
if (local_exact != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) {
|
||||
if (injail)
|
||||
return (inp);
|
||||
else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
|
||||
else
|
||||
local_exact = inp;
|
||||
} else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
|
||||
if (injail)
|
||||
jail_wild = inp;
|
||||
else
|
||||
local_wild = inp;
|
||||
}
|
||||
}
|
||||
return (local_wild);
|
||||
}
|
||||
} /* LIST_FOREACH */
|
||||
|
||||
if (jail_wild != NULL)
|
||||
return (jail_wild);
|
||||
if (local_exact != NULL)
|
||||
return (local_exact);
|
||||
if (local_wild != NULL)
|
||||
return (local_wild);
|
||||
} /* if (wildcard == INPLOOKUP_WILDCARD) */
|
||||
|
||||
/*
|
||||
* Not found.
|
||||
|
@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/vimage.h>
|
||||
@ -235,6 +236,11 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
if (*errorp != 0)
|
||||
return (NULL);
|
||||
}
|
||||
if (cred != NULL && prison_local_ip6(cred, &srcsock.sin6_addr,
|
||||
(inp != NULL && (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) {
|
||||
*errorp = EADDRNOTAVAIL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
|
||||
if (ia6 == NULL ||
|
||||
@ -252,6 +258,11 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
* Otherwise, if the socket has already bound the source, just use it.
|
||||
*/
|
||||
if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
|
||||
if (cred != NULL && prison_local_ip6(cred, &inp->in6p_laddr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) {
|
||||
*errorp = EADDRNOTAVAIL;
|
||||
return (NULL);
|
||||
}
|
||||
return (&inp->in6p_laddr);
|
||||
}
|
||||
|
||||
@ -303,6 +314,12 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
if (!V_ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
|
||||
continue;
|
||||
|
||||
if (cred != NULL &&
|
||||
prison_local_ip6(cred, &ia->ia_addr.sin6_addr,
|
||||
(inp != NULL &&
|
||||
(inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
|
||||
continue;
|
||||
|
||||
/* Rule 1: Prefer same address */
|
||||
if (IN6_ARE_ADDR_EQUAL(&dst, &ia->ia_addr.sin6_addr)) {
|
||||
ia_best = ia;
|
||||
@ -784,6 +801,10 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred)
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
||||
if (prison_local_ip6(cred, laddr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
|
||||
return(EINVAL);
|
||||
|
||||
/* XXX: this is redundant when called from in6_pcbbind */
|
||||
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
|
||||
wild = INPLOOKUP_WILDCARD;
|
||||
|
@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
@ -162,6 +163,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
|
||||
INP_INFO_RLOCK(&V_ripcbinfo);
|
||||
LIST_FOREACH(in6p, &V_ripcb, inp_list) {
|
||||
/* XXX inp locking */
|
||||
if ((in6p->in6p_vflag & INP_IPV6) == 0)
|
||||
continue;
|
||||
if (in6p->in6p_ip6_nxt &&
|
||||
@ -173,6 +175,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
|
||||
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
|
||||
continue;
|
||||
if (jailed(in6p->inp_cred)) {
|
||||
if (!prison_check_ip6(in6p->inp_cred, &ip6->ip6_dst))
|
||||
continue;
|
||||
}
|
||||
INP_RLOCK(in6p);
|
||||
if (in6p->in6p_cksum != -1) {
|
||||
V_rip6stat.rip6s_isum++;
|
||||
@ -401,6 +407,11 @@ rip6_output(m, va_alist)
|
||||
error = EADDRNOTAVAIL;
|
||||
goto bad;
|
||||
}
|
||||
if (jailed(in6p->inp_cred))
|
||||
if (prison_getip6(in6p->inp_cred, in6a) != 0) {
|
||||
error = EPERM;
|
||||
goto bad;
|
||||
}
|
||||
ip6->ip6_src = *in6a;
|
||||
|
||||
if (oifp && scope_ambiguous) {
|
||||
@ -663,6 +674,8 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
|
||||
if (nam->sa_len != sizeof(*addr))
|
||||
return (EINVAL);
|
||||
if (!prison_check_ip6(td->td_ucred, &addr->sin6_addr))
|
||||
return (EADDRNOTAVAIL);
|
||||
if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
|
||||
return (EADDRNOTAVAIL);
|
||||
if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
|
||||
|
@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "opt_mac.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mbuf.h>
|
||||
@ -860,6 +861,12 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
goto out;
|
||||
}
|
||||
in6_sin6_2_sin(&sin, sin6_p);
|
||||
if (td && jailed(td->td_ucred))
|
||||
if (prison_remote_ip4(td->td_ucred,
|
||||
&sin.sin_addr) != 0) {
|
||||
error = EAFNOSUPPORT;
|
||||
goto out;
|
||||
}
|
||||
error = in_pcbconnect(inp, (struct sockaddr *)&sin,
|
||||
td->td_ucred);
|
||||
if (error == 0) {
|
||||
@ -874,6 +881,13 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
error = EISCONN;
|
||||
goto out;
|
||||
}
|
||||
if (td && jailed(td->td_ucred)) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
if (prison_remote_ip6(td->td_ucred, &sin6->sin6_addr) != 0) {
|
||||
error = EAFNOSUPPORT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
error = in6_pcbconnect(inp, nam, td->td_ucred);
|
||||
if (error == 0) {
|
||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -132,6 +132,7 @@ typedef struct _cpuset {
|
||||
#define CPU_WHICH_PID 2 /* Specifies a process id. */
|
||||
#define CPU_WHICH_CPUSET 3 /* Specifies a set id. */
|
||||
#define CPU_WHICH_IRQ 4 /* Specifies an irq #. */
|
||||
#define CPU_WHICH_JAIL 5 /* Specifies a jail id. */
|
||||
|
||||
/*
|
||||
* Reserved cpuset identifiers.
|
||||
@ -168,11 +169,15 @@ struct cpuset {
|
||||
#define CPU_SET_RDONLY 0x0002 /* No modification allowed. */
|
||||
|
||||
extern cpuset_t *cpuset_root;
|
||||
struct proc;
|
||||
struct thread;
|
||||
|
||||
struct cpuset *cpuset_thread0(void);
|
||||
struct cpuset *cpuset_ref(struct cpuset *);
|
||||
void cpuset_rel(struct cpuset *);
|
||||
int cpuset_setthread(lwpid_t id, cpuset_t *);
|
||||
int cpuset_create_root(struct thread *, struct cpuset **);
|
||||
int cpuset_setproc_update_set(struct proc *, struct cpuset *);
|
||||
|
||||
#else
|
||||
__BEGIN_DECLS
|
||||
|
@ -13,21 +13,74 @@
|
||||
#ifndef _SYS_JAIL_H_
|
||||
#define _SYS_JAIL_H_
|
||||
|
||||
struct jail {
|
||||
#ifdef _KERNEL
|
||||
struct jail_v0 {
|
||||
u_int32_t version;
|
||||
char *path;
|
||||
char *hostname;
|
||||
u_int32_t ip_number;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct jail {
|
||||
uint32_t version;
|
||||
char *path;
|
||||
char *hostname;
|
||||
char *jailname;
|
||||
uint32_t ip4s;
|
||||
uint32_t ip6s;
|
||||
struct in_addr *ip4;
|
||||
struct in6_addr *ip6;
|
||||
};
|
||||
#define JAIL_API_VERSION 2
|
||||
|
||||
/*
|
||||
* For all xprison structs, always keep the pr_version an int and
|
||||
* the first variable so userspace can easily distinguish them.
|
||||
*/
|
||||
#ifndef _KERNEL
|
||||
struct xprison_v1 {
|
||||
int pr_version;
|
||||
int pr_id;
|
||||
char pr_path[MAXPATHLEN];
|
||||
char pr_host[MAXHOSTNAMELEN];
|
||||
u_int32_t pr_ip;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct xprison {
|
||||
int pr_version;
|
||||
int pr_id;
|
||||
int pr_state;
|
||||
cpusetid_t pr_cpusetid;
|
||||
char pr_path[MAXPATHLEN];
|
||||
char pr_host[MAXHOSTNAMELEN];
|
||||
u_int32_t pr_ip;
|
||||
char pr_name[MAXHOSTNAMELEN];
|
||||
uint32_t pr_ip4s;
|
||||
uint32_t pr_ip6s;
|
||||
#if 0
|
||||
/*
|
||||
* sizeof(xprison) will be malloced + size needed for all
|
||||
* IPv4 and IPv6 addesses. Offsets are based numbers of addresses.
|
||||
*/
|
||||
struct in_addr pr_ip4[];
|
||||
struct in6_addr pr_ip6[];
|
||||
#endif
|
||||
};
|
||||
#define XPRISON_VERSION 1
|
||||
#define XPRISON_VERSION 3
|
||||
|
||||
static const struct prison_state {
|
||||
int pr_state;
|
||||
const char * state_name;
|
||||
} prison_states[] = {
|
||||
#define PRISON_STATE_INVALID 0
|
||||
{ PRISON_STATE_INVALID, "INVALID" },
|
||||
#define PRISON_STATE_ALIVE 1
|
||||
{ PRISON_STATE_ALIVE, "ALIVE" },
|
||||
#define PRISON_STATE_DYING 2
|
||||
{ PRISON_STATE_DYING, "DYING" },
|
||||
};
|
||||
|
||||
|
||||
#ifndef _KERNEL
|
||||
|
||||
@ -52,6 +105,8 @@ MALLOC_DECLARE(M_PRISON);
|
||||
|
||||
#include <sys/osd.h>
|
||||
|
||||
struct cpuset;
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -68,15 +123,22 @@ struct prison {
|
||||
LIST_ENTRY(prison) pr_list; /* (a) all prisons */
|
||||
int pr_id; /* (c) prison id */
|
||||
int pr_ref; /* (p) refcount */
|
||||
int pr_state; /* (p) prison state */
|
||||
int pr_nprocs; /* (p) process count */
|
||||
char pr_path[MAXPATHLEN]; /* (c) chroot path */
|
||||
struct cpuset *pr_cpuset; /* (p) cpuset */
|
||||
struct vnode *pr_root; /* (c) vnode to rdir */
|
||||
char pr_host[MAXHOSTNAMELEN]; /* (p) jail hostname */
|
||||
u_int32_t pr_ip; /* (c) ip addr host */
|
||||
char pr_name[MAXHOSTNAMELEN]; /* (c) admin jail name */
|
||||
void *pr_linux; /* (p) linux abi */
|
||||
int pr_securelevel; /* (p) securelevel */
|
||||
struct task pr_task; /* (d) destroy task */
|
||||
struct mtx pr_mtx;
|
||||
struct osd pr_osd; /* (p) additional data */
|
||||
int pr_ip4s; /* (c) number of v4 IPs */
|
||||
struct in_addr *pr_ip4; /* (c) v4 IPs of jail */
|
||||
int pr_ip6s; /* (c) number of v6 IPs */
|
||||
struct in6_addr *pr_ip6; /* (c) v6 IPs of jail */
|
||||
};
|
||||
#endif /* _KERNEL || _WANT_PRISON */
|
||||
|
||||
@ -104,6 +166,8 @@ struct ucred;
|
||||
struct mount;
|
||||
struct sockaddr;
|
||||
struct statfs;
|
||||
struct thread;
|
||||
int kern_jail(struct thread *, struct jail *);
|
||||
int jailed(struct ucred *cred);
|
||||
void getcredhostname(struct ucred *cred, char *, size_t);
|
||||
int prison_check(struct ucred *cred1, struct ucred *cred2);
|
||||
@ -113,13 +177,22 @@ void prison_enforce_statfs(struct ucred *cred, struct mount *mp,
|
||||
struct prison *prison_find(int prid);
|
||||
void prison_free(struct prison *pr);
|
||||
void prison_free_locked(struct prison *pr);
|
||||
u_int32_t prison_getip(struct ucred *cred);
|
||||
void prison_hold(struct prison *pr);
|
||||
void prison_hold_locked(struct prison *pr);
|
||||
void prison_proc_hold(struct prison *);
|
||||
void prison_proc_free(struct prison *);
|
||||
int prison_getip4(struct ucred *cred, struct in_addr *ia);
|
||||
int prison_local_ip4(struct ucred *cred, struct in_addr *ia);
|
||||
int prison_remote_ip4(struct ucred *cred, struct in_addr *ia);
|
||||
int prison_check_ip4(struct ucred *cred, struct in_addr *ia);
|
||||
#ifdef INET6
|
||||
int prison_getip6(struct ucred *, struct in6_addr *);
|
||||
int prison_local_ip6(struct ucred *, struct in6_addr *, int);
|
||||
int prison_remote_ip6(struct ucred *, struct in6_addr *);
|
||||
int prison_check_ip6(struct ucred *, struct in6_addr *);
|
||||
#endif
|
||||
int prison_if(struct ucred *cred, struct sockaddr *sa);
|
||||
int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
|
||||
int prison_priv_check(struct ucred *cred, int priv);
|
||||
void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
|
||||
|
||||
/*
|
||||
* Kernel jail services.
|
||||
|
@ -57,7 +57,7 @@
|
||||
* is created, otherwise 1.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 800055 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 800056 /* Master, propagated to newvers */
|
||||
|
||||
#ifndef LOCORE
|
||||
#include <sys/types.h>
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 11, 2008
|
||||
.Dd November 29, 2008
|
||||
.Dt CPUSET 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -43,10 +43,10 @@
|
||||
.Nm
|
||||
.Op Fl cr
|
||||
.Op Fl l Ar cpu-list
|
||||
.Op Fl p Ar pid | Fl r Ar tid | Fl s Ar setid
|
||||
.Op Fl j Ar jailid | Fl p Ar pid | Fl r Ar tid | Fl s Ar setid | Fl x Ar irq
|
||||
.Nm
|
||||
.Op Fl cgir
|
||||
.Op Fl p Ar pid | Fl r Ar tid | Fl s Ar setid
|
||||
.Op Fl j Ar jailid | Fl p Ar pid | Fl r Ar tid | Fl s Ar setid | Fl x Ar irq
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -56,8 +56,8 @@ about processor binding, sets, and available processors in the system.
|
||||
.Pp
|
||||
.Nm
|
||||
requires a target to modify or query.
|
||||
The target may be specified as a command, process id, thread id, or a
|
||||
cpuset id.
|
||||
The target may be specified as a command, process id, thread id, a
|
||||
cpuset id, an irq or a jail id.
|
||||
Using
|
||||
.Fl g
|
||||
the target's set id or mask may be queried.
|
||||
@ -111,6 +111,8 @@ the id of the target.
|
||||
When used with the
|
||||
.Fl g
|
||||
option print the id rather than the valid mask of the target.
|
||||
.It Fl j Ar jailid
|
||||
Specifies a jail id as the target of the operation.
|
||||
.It Fl l Ar cpu-list
|
||||
Specifies a list of CPUs to apply to a target.
|
||||
Specification may include
|
||||
@ -124,6 +126,8 @@ The requested operation should reference the root set available via the
|
||||
target specifier.
|
||||
.It Fl t Ar tid
|
||||
Specifies a thread id as the target of the operation.
|
||||
.It Fl x Ar irq
|
||||
Specifies an irq as the target of the operation.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
|
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
int cflag;
|
||||
int gflag;
|
||||
int iflag;
|
||||
int jflag;
|
||||
int lflag;
|
||||
int pflag;
|
||||
int rflag;
|
||||
@ -153,7 +154,7 @@ printset(cpuset_t *mask)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq" };
|
||||
const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq", "jail" };
|
||||
const char *levelnames[] = { NULL, " root", " cpuset", "" };
|
||||
|
||||
static void
|
||||
@ -198,7 +199,7 @@ main(int argc, char *argv[])
|
||||
level = CPU_LEVEL_WHICH;
|
||||
which = CPU_WHICH_PID;
|
||||
id = pid = tid = setid = -1;
|
||||
while ((ch = getopt(argc, argv, "cgil:p:rs:t:x:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "cgij:l:p:rs:t:x:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
if (rflag)
|
||||
@ -212,6 +213,11 @@ main(int argc, char *argv[])
|
||||
case 'i':
|
||||
iflag = 1;
|
||||
break;
|
||||
case 'j':
|
||||
jflag = 1;
|
||||
which = CPU_WHICH_JAIL;
|
||||
id = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
lflag = 1;
|
||||
parselist(optarg, &mask);
|
||||
@ -252,7 +258,7 @@ main(int argc, char *argv[])
|
||||
if (argc || lflag)
|
||||
usage();
|
||||
/* Only one identity specifier. */
|
||||
if (xflag + sflag + pflag + tflag > 1)
|
||||
if (jflag + xflag + sflag + pflag + tflag > 1)
|
||||
usage();
|
||||
if (iflag)
|
||||
printsetid();
|
||||
@ -266,7 +272,7 @@ main(int argc, char *argv[])
|
||||
* The user wants to run a command with a set and possibly cpumask.
|
||||
*/
|
||||
if (argc) {
|
||||
if (pflag | rflag | tflag | xflag)
|
||||
if (pflag | rflag | tflag | xflag | jflag)
|
||||
usage();
|
||||
if (sflag) {
|
||||
if (cpuset_setid(CPU_WHICH_PID, -1, setid))
|
||||
@ -292,10 +298,10 @@ main(int argc, char *argv[])
|
||||
if (!lflag && !sflag)
|
||||
usage();
|
||||
/* You can only set a mask on a thread. */
|
||||
if (tflag && (sflag | pflag | xflag))
|
||||
if (tflag && (sflag | pflag | xflag | jflag))
|
||||
usage();
|
||||
/* You can only set a mask on an irq. */
|
||||
if (xflag && (pflag | sflag | tflag))
|
||||
if (xflag && (jflag | pflag | sflag | tflag))
|
||||
usage();
|
||||
if (pflag && sflag) {
|
||||
if (cpuset_setid(CPU_WHICH_PID, pid, setid))
|
||||
@ -325,8 +331,8 @@ usage(void)
|
||||
fprintf(stderr,
|
||||
" cpuset [-l cpu-list] [-s setid] -p pid\n");
|
||||
fprintf(stderr,
|
||||
" cpuset [-cr] [-l cpu-list] [-p pid | -t tid | -s setid | -x irq]\n");
|
||||
" cpuset [-cr] [-l cpu-list] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n");
|
||||
fprintf(stderr,
|
||||
" cpuset [-cgir] [-p pid | -t tid | -s setid | -x irq]\n");
|
||||
" cpuset [-cgir] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= jail
|
||||
MAN= jail.8
|
||||
DPADD= ${LIBUTIL}
|
||||
@ -7,4 +9,8 @@ LDADD= -lutil
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET6
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -33,7 +33,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 5, 2007
|
||||
.Dd November 29, 2008
|
||||
.Dt JAIL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -41,11 +41,12 @@
|
||||
.Nd "imprison process and its descendants"
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl i
|
||||
.Op Fl hi
|
||||
.Op Fl n Ar jailname
|
||||
.Op Fl J Ar jid_file
|
||||
.Op Fl s Ar securelevel
|
||||
.Op Fl l u Ar username | Fl U Ar username
|
||||
.Ar path hostname ip-number command ...
|
||||
.Ar path hostname [ip[,..]] command ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -53,8 +54,26 @@ utility imprisons a process and all future descendants.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width ".Fl u Ar username"
|
||||
.It Fl h
|
||||
Resolve
|
||||
.Va hostname
|
||||
and add all IP addresses returned by the resolver
|
||||
to the list of
|
||||
.Va ip-addresses
|
||||
for this prison.
|
||||
This may affect default address selection for outgoing IPv4 connections
|
||||
of prisons.
|
||||
The address first returned by the resolver for the IPv4 address family
|
||||
will be used as default.
|
||||
For IPv6 source address selection is done by a well defined algorithm.
|
||||
.It Fl i
|
||||
Output the jail identifier of the newly created jail.
|
||||
.It Fl n Ar jailname
|
||||
Assign and administrative name to the jail that can be used for management
|
||||
or auditing purposes.
|
||||
The system will
|
||||
.Sy not enforce
|
||||
the name to be unique.
|
||||
.It Fl J Ar jid_file
|
||||
Write a
|
||||
.Ar jid_file
|
||||
@ -92,8 +111,14 @@ should run.
|
||||
Directory which is to be the root of the prison.
|
||||
.It Ar hostname
|
||||
Hostname of the prison.
|
||||
.It Ar ip-number
|
||||
IP number assigned to the prison.
|
||||
.It Ar ip-addresses
|
||||
None, one or more IPv4 and IPv6 addresses assigned to the prison.
|
||||
The first address of each address family that was assigned to the jail will
|
||||
be used as the source address in case source address selection on unbound
|
||||
sockets cannot find a better match.
|
||||
It is only possible to start multiple jails with the same IP address,
|
||||
if none of the jails has more than this single overlapping IP address
|
||||
assigned to itself for the address family in question.
|
||||
.It Ar command
|
||||
Pathname of the program which is to be executed.
|
||||
.El
|
||||
@ -179,7 +204,7 @@ is to disable IP services on the host system that listen on all local
|
||||
IP addresses for a service.
|
||||
If a network service is present in the host environment that binds all
|
||||
available IP addresses rather than specific IP addresses, it may service
|
||||
requests sent to jail IP addresses.
|
||||
requests sent to jail IP addresses if the jail did not bind the port.
|
||||
This means changing
|
||||
.Xr inetd 8
|
||||
to only listen on the
|
||||
@ -555,6 +580,9 @@ command can be used to find file system types available for mount from within
|
||||
a jail.
|
||||
This functionality is disabled by default, but can be enabled by setting this
|
||||
MIB entry to 1.
|
||||
.It Va security.jail.jail_max_af_ips
|
||||
This MIB entry determines how may address per address family a prison
|
||||
may have. The default is 255.
|
||||
.El
|
||||
.Pp
|
||||
The read-only sysctl variable
|
||||
@ -622,6 +650,12 @@ who contributed it to
|
||||
.An Robert Watson
|
||||
wrote the extended documentation, found a few bugs, added
|
||||
a few new features, and cleaned up the userland jail environment.
|
||||
.Pp
|
||||
.An Bjoern A. Zeeb
|
||||
added multi-IP jail support for IPv4 and IPv6 based on a patch
|
||||
originally done by
|
||||
.An Pawel Jakub Dawidek
|
||||
for IPv4.
|
||||
.Sh BUGS
|
||||
Jail currently lacks the ability to allow access to
|
||||
specific jail information via
|
||||
|
@ -12,10 +12,14 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -25,12 +29,34 @@ __FBSDID("$FreeBSD$");
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(void);
|
||||
static void usage(void);
|
||||
static int add_addresses(struct addrinfo *);
|
||||
static struct in_addr *copy_addr4(void);
|
||||
#ifdef INET6
|
||||
static struct in6_addr *copy_addr6(void);
|
||||
#endif
|
||||
|
||||
extern char **environ;
|
||||
|
||||
struct addr4entry {
|
||||
STAILQ_ENTRY(addr4entry) addr4entries;
|
||||
struct in_addr ip4;
|
||||
int count;
|
||||
};
|
||||
struct addr6entry {
|
||||
STAILQ_ENTRY(addr6entry) addr6entries;
|
||||
#ifdef INET6
|
||||
struct in6_addr ip6;
|
||||
#endif
|
||||
int count;
|
||||
};
|
||||
STAILQ_HEAD(addr4head, addr4entry) addr4 = STAILQ_HEAD_INITIALIZER(addr4);
|
||||
STAILQ_HEAD(addr6head, addr6entry) addr6 = STAILQ_HEAD_INITIALIZER(addr6);
|
||||
|
||||
#define GET_USER_INFO do { \
|
||||
pwd = getpwnam(username); \
|
||||
if (pwd == NULL) { \
|
||||
@ -53,22 +79,26 @@ main(int argc, char **argv)
|
||||
login_cap_t *lcap = NULL;
|
||||
struct jail j;
|
||||
struct passwd *pwd = NULL;
|
||||
struct in_addr in;
|
||||
gid_t groups[NGROUPS];
|
||||
int ch, i, iflag, Jflag, lflag, ngroups, securelevel, uflag, Uflag;
|
||||
char path[PATH_MAX], *ep, *username, *JidFile;
|
||||
int ch, error, i, ngroups, securelevel;
|
||||
int hflag, iflag, Jflag, lflag, uflag, Uflag;
|
||||
char path[PATH_MAX], *jailname, *ep, *username, *JidFile, *ip;
|
||||
static char *cleanenv;
|
||||
const char *shell, *p = NULL;
|
||||
long ltmp;
|
||||
FILE *fp;
|
||||
struct addrinfo hints, *res0;
|
||||
|
||||
iflag = Jflag = lflag = uflag = Uflag = 0;
|
||||
hflag = iflag = Jflag = lflag = uflag = Uflag = 0;
|
||||
securelevel = -1;
|
||||
username = JidFile = cleanenv = NULL;
|
||||
jailname = username = JidFile = cleanenv = NULL;
|
||||
fp = NULL;
|
||||
|
||||
while ((ch = getopt(argc, argv, "ils:u:U:J:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "hiln:s:u:U:J:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
hflag = 1;
|
||||
break;
|
||||
case 'i':
|
||||
iflag = 1;
|
||||
break;
|
||||
@ -76,6 +106,9 @@ main(int argc, char **argv)
|
||||
JidFile = optarg;
|
||||
Jflag = 1;
|
||||
break;
|
||||
case 'n':
|
||||
jailname = optarg;
|
||||
break;
|
||||
case 's':
|
||||
ltmp = strtol(optarg, &ep, 0);
|
||||
if (*ep || ep == optarg || ltmp > INT_MAX || !ltmp)
|
||||
@ -111,13 +144,62 @@ main(int argc, char **argv)
|
||||
err(1, "realpath: %s", argv[0]);
|
||||
if (chdir(path) != 0)
|
||||
err(1, "chdir: %s", path);
|
||||
/* Initialize struct jail. */
|
||||
memset(&j, 0, sizeof(j));
|
||||
j.version = 0;
|
||||
j.version = JAIL_API_VERSION;
|
||||
j.path = path;
|
||||
j.hostname = argv[1];
|
||||
if (inet_aton(argv[2], &in) == 0)
|
||||
errx(1, "Could not make sense of ip-number: %s", argv[2]);
|
||||
j.ip_number = ntohl(in.s_addr);
|
||||
if (jailname != NULL)
|
||||
j.jailname = jailname;
|
||||
|
||||
/* Handle IP addresses. If requested resolve hostname too. */
|
||||
bzero(&hints, sizeof(struct addrinfo));
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (JAIL_API_VERSION < 2)
|
||||
hints.ai_family = PF_INET;
|
||||
else
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
/* Handle hostname. */
|
||||
if (hflag != 0) {
|
||||
error = getaddrinfo(j.hostname, NULL, &hints, &res0);
|
||||
if (error != 0)
|
||||
errx(1, "failed to handle hostname: %s",
|
||||
gai_strerror(error));
|
||||
error = add_addresses(res0);
|
||||
freeaddrinfo(res0);
|
||||
if (error != 0)
|
||||
errx(1, "failed to add addresses.");
|
||||
}
|
||||
/* Handle IP addresses. */
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
ip = strtok(argv[2], ",");
|
||||
while (ip != NULL) {
|
||||
error = getaddrinfo(ip, NULL, &hints, &res0);
|
||||
if (error != 0)
|
||||
errx(1, "failed to handle ip: %s", gai_strerror(error));
|
||||
error = add_addresses(res0);
|
||||
freeaddrinfo(res0);
|
||||
if (error != 0)
|
||||
errx(1, "failed to add addresses.");
|
||||
ip = strtok(NULL, ",");
|
||||
}
|
||||
/* Count IP addresses and add them to struct jail. */
|
||||
if (!STAILQ_EMPTY(&addr4)) {
|
||||
j.ip4s = STAILQ_FIRST(&addr4)->count;
|
||||
j.ip4 = copy_addr4();
|
||||
if (j.ip4s > 0 && j.ip4 == NULL)
|
||||
errx(1, "copy_addr4()");
|
||||
}
|
||||
#ifdef INET6
|
||||
if (!STAILQ_EMPTY(&addr6)) {
|
||||
j.ip6s = STAILQ_FIRST(&addr6)->count;
|
||||
j.ip6 = copy_addr6();
|
||||
if (j.ip6s > 0 && j.ip6 == NULL)
|
||||
errx(1, "copy_addr6()");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Jflag) {
|
||||
fp = fopen(JidFile, "w");
|
||||
if (fp == NULL)
|
||||
@ -125,7 +207,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
i = jail(&j);
|
||||
if (i == -1)
|
||||
err(1, "jail");
|
||||
err(1, "syscall failed with");
|
||||
if (iflag) {
|
||||
printf("%d\n", i);
|
||||
fflush(stdout);
|
||||
@ -183,8 +265,148 @@ usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "%s%s%s\n",
|
||||
"usage: jail [-i] [-J jid_file] [-s securelevel] [-l -u ",
|
||||
"username | -U username]",
|
||||
" path hostname ip-number command ...");
|
||||
"usage: jail [-hi] [-n jailname] [-J jid_file] ",
|
||||
"[-s securelevel] [-l -u username | -U username] ",
|
||||
"path hostname [ip[,..]] command ...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
add_addresses(struct addrinfo *res0)
|
||||
{
|
||||
int error;
|
||||
struct addrinfo *res;
|
||||
struct addr4entry *a4p;
|
||||
struct sockaddr_in *sai;
|
||||
#ifdef INET6
|
||||
struct addr6entry *a6p;
|
||||
struct sockaddr_in6 *sai6;
|
||||
#endif
|
||||
int count;
|
||||
|
||||
error = 0;
|
||||
for (res = res0; res && error == 0; res = res->ai_next) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
sai = (struct sockaddr_in *)(void *)res->ai_addr;
|
||||
STAILQ_FOREACH(a4p, &addr4, addr4entries) {
|
||||
if (bcmp(&sai->sin_addr, &a4p->ip4,
|
||||
sizeof(struct in_addr)) == 0) {
|
||||
err(1, "Ignoring duplicate IPv4 address.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
a4p = (struct addr4entry *) malloc(
|
||||
sizeof(struct addr4entry));
|
||||
if (a4p == NULL) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
bzero(a4p, sizeof(struct addr4entry));
|
||||
bcopy(&sai->sin_addr, &a4p->ip4,
|
||||
sizeof(struct in_addr));
|
||||
if (!STAILQ_EMPTY(&addr4))
|
||||
count = STAILQ_FIRST(&addr4)->count;
|
||||
else
|
||||
count = 0;
|
||||
STAILQ_INSERT_TAIL(&addr4, a4p, addr4entries);
|
||||
STAILQ_FIRST(&addr4)->count = count + 1;
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
sai6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
|
||||
STAILQ_FOREACH(a6p, &addr6, addr6entries) {
|
||||
if (bcmp(&sai6->sin6_addr, &a6p->ip6,
|
||||
sizeof(struct in6_addr)) == 0) {
|
||||
err(1, "Ignoring duplicate IPv6 address.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
a6p = (struct addr6entry *) malloc(
|
||||
sizeof(struct addr6entry));
|
||||
if (a6p == NULL) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
bzero(a6p, sizeof(struct addr6entry));
|
||||
bcopy(&sai6->sin6_addr, &a6p->ip6,
|
||||
sizeof(struct in6_addr));
|
||||
if (!STAILQ_EMPTY(&addr6))
|
||||
count = STAILQ_FIRST(&addr6)->count;
|
||||
else
|
||||
count = 0;
|
||||
STAILQ_INSERT_TAIL(&addr6, a6p, addr6entries);
|
||||
STAILQ_FIRST(&addr6)->count = count + 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
err(1, "Address family %d not supported. Ignoring.\n",
|
||||
res->ai_family);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct in_addr *
|
||||
copy_addr4(void)
|
||||
{
|
||||
size_t len;
|
||||
struct in_addr *ip4s, *p, ia;
|
||||
struct addr4entry *a4p;
|
||||
|
||||
if (STAILQ_EMPTY(&addr4))
|
||||
return NULL;
|
||||
|
||||
len = STAILQ_FIRST(&addr4)->count * sizeof(struct in_addr);
|
||||
|
||||
ip4s = p = (struct in_addr *)malloc(len);
|
||||
if (ip4s == NULL)
|
||||
return (NULL);
|
||||
|
||||
bzero(p, len);
|
||||
|
||||
while (!STAILQ_EMPTY(&addr4)) {
|
||||
a4p = STAILQ_FIRST(&addr4);
|
||||
STAILQ_REMOVE_HEAD(&addr4, addr4entries);
|
||||
ia.s_addr = a4p->ip4.s_addr;
|
||||
bcopy(&ia, p, sizeof(struct in_addr));
|
||||
p++;
|
||||
free(a4p);
|
||||
}
|
||||
|
||||
return (ip4s);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
static struct in6_addr *
|
||||
copy_addr6(void)
|
||||
{
|
||||
size_t len;
|
||||
struct in6_addr *ip6s, *p;
|
||||
struct addr6entry *a6p;
|
||||
|
||||
if (STAILQ_EMPTY(&addr6))
|
||||
return NULL;
|
||||
|
||||
len = STAILQ_FIRST(&addr6)->count * sizeof(struct in6_addr);
|
||||
|
||||
ip6s = p = (struct in6_addr *)malloc(len);
|
||||
if (ip6s == NULL)
|
||||
return (NULL);
|
||||
|
||||
bzero(p, len);
|
||||
|
||||
while (!STAILQ_EMPTY(&addr6)) {
|
||||
a6p = STAILQ_FIRST(&addr6);
|
||||
STAILQ_REMOVE_HEAD(&addr6, addr6entries);
|
||||
bcopy(&a6p->ip6, p, sizeof(struct in6_addr));
|
||||
p++;
|
||||
free(a6p);
|
||||
}
|
||||
|
||||
return (ip6s);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -6,4 +6,6 @@ DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
WARNS?= 6
|
||||
|
||||
CFLAGS+= -DSUPPORT_OLD_XPRISON
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 26, 2008
|
||||
.Dd November 29, 2008
|
||||
.Dt JEXEC 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -34,22 +34,36 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl u Ar username | Fl U Ar username
|
||||
.Op Fl h Ar hostname | Fl h Ar ip-number | Ar jid
|
||||
.Ar command ...
|
||||
.Op Fl n Ar jailname
|
||||
.Ar jid command ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility executes
|
||||
.Ar command
|
||||
inside the jail identified by
|
||||
.Ar hostname
|
||||
inside the jail identified by either
|
||||
.Ar jailname
|
||||
or
|
||||
.Ar ip-number
|
||||
or
|
||||
.Ar jid .
|
||||
.Ar jid
|
||||
or both.
|
||||
.Pp
|
||||
If the jail cannot be identified uniquely by the given parameters,
|
||||
an error message is printed.
|
||||
.Nm
|
||||
will also check the state of the jail (once supported) to be
|
||||
.Dv ALIVE
|
||||
and ignore jails in other states.
|
||||
The mandatory argument
|
||||
.Ar jid
|
||||
is the unique jail identifier as given by
|
||||
.Xr jls 8 .
|
||||
In case you only want to match on other criteria, give an empty string.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width indent
|
||||
.It Fl n Ar jailname
|
||||
The name of the jail, if given upon creation of the jail.
|
||||
This is not the hostname of the jail.
|
||||
.It Fl u Ar username
|
||||
The user name from host environment as whom the
|
||||
.Ar command
|
||||
@ -59,9 +73,6 @@ The user name from jailed environment as whom the
|
||||
.Ar command
|
||||
should run.
|
||||
.El
|
||||
.Sh "CAUTIONS"
|
||||
Only jid is guaranteed to uniquely identify a jail.
|
||||
Hostname or ip-number only work here if matched to one unique jail.
|
||||
.Sh SEE ALSO
|
||||
.Xr jail_attach 2 ,
|
||||
.Xr jail 8 ,
|
||||
@ -71,3 +82,13 @@ The
|
||||
.Nm
|
||||
utility was added in
|
||||
.Fx 5.1 .
|
||||
.Sh BUGS
|
||||
If the jail is not identified by
|
||||
.Ar jid
|
||||
there is a possible race in between the lookup of the jail
|
||||
and executing the command inside the jail.
|
||||
Giving a
|
||||
.Ar jid
|
||||
has a similar race as another process can stop the jail and
|
||||
start another one after the user looked up the
|
||||
.Ar jid .
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
|
||||
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -30,20 +31,171 @@
|
||||
#include <sys/jail.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <login_cap.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static void usage(void);
|
||||
static int addr2jid(const char *addr);
|
||||
|
||||
#ifdef SUPPORT_OLD_XPRISON
|
||||
static
|
||||
char *lookup_xprison_v1(void *p, char *end, int *id)
|
||||
{
|
||||
struct xprison_v1 *xp;
|
||||
|
||||
if (id == NULL)
|
||||
errx(1, "Internal error. Invalid ID pointer.");
|
||||
|
||||
if ((char *)p + sizeof(struct xprison_v1) > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
|
||||
xp = (struct xprison_v1 *)p;
|
||||
|
||||
*id = xp->pr_id;
|
||||
return ((char *)(xp + 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
char *lookup_xprison_v3(void *p, char *end, int *id, char *jailname)
|
||||
{
|
||||
struct xprison *xp;
|
||||
char *q;
|
||||
int ok;
|
||||
|
||||
if (id == NULL)
|
||||
errx(1, "Internal error. Invalid ID pointer.");
|
||||
|
||||
if ((char *)p + sizeof(struct xprison) > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
|
||||
xp = (struct xprison *)p;
|
||||
ok = 1;
|
||||
|
||||
/* Jail state and name. */
|
||||
if (xp->pr_state < 0 || xp->pr_state >
|
||||
(int)((sizeof(prison_states) / sizeof(struct prison_state))))
|
||||
errx(1, "Invalid jail state.");
|
||||
else if (xp->pr_state != PRISON_STATE_ALIVE)
|
||||
ok = 0;
|
||||
if (jailname != NULL) {
|
||||
if (xp->pr_name == NULL)
|
||||
ok = 0;
|
||||
else if (strcmp(jailname, xp->pr_name) != 0)
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
q = (char *)(xp + 1);
|
||||
/* IPv4 addresses. */
|
||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
||||
if ((char *)q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
/* IPv6 addresses. */
|
||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
||||
if ((char *)q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
|
||||
if (ok)
|
||||
*id = xp->pr_id;
|
||||
return (q);
|
||||
}
|
||||
|
||||
static int
|
||||
lookup_jail(int jid, char *jailname)
|
||||
{
|
||||
size_t i, j, len;
|
||||
void *p, *q;
|
||||
int version, id, xid, count;
|
||||
|
||||
if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
|
||||
j = len;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (len <= 0)
|
||||
exit(0);
|
||||
p = q = malloc(len);
|
||||
if (p == NULL)
|
||||
err(1, "malloc()");
|
||||
|
||||
if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
|
||||
if (errno == ENOMEM) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
len += j;
|
||||
continue;
|
||||
}
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (p == NULL)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
if (len < sizeof(int))
|
||||
errx(1, "This is no prison. Kernel and userland out of sync?");
|
||||
version = *(int *)p;
|
||||
if (version > XPRISON_VERSION)
|
||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
||||
|
||||
count = 0;
|
||||
xid = -1;
|
||||
for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
|
||||
version = *(int *)q;
|
||||
if (version > XPRISON_VERSION)
|
||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
||||
id = -1;
|
||||
switch (version) {
|
||||
#ifdef SUPPORT_OLD_XPRISON
|
||||
case 1:
|
||||
if (jailname != NULL)
|
||||
errx(1, "Version 1 prisons did not "
|
||||
"support jail names.");
|
||||
q = lookup_xprison_v1(q, (char *)p + len, &id);
|
||||
break;
|
||||
case 2:
|
||||
errx(1, "Version 2 was used by multi-IPv4 jail "
|
||||
"implementations that never made it into the "
|
||||
"official kernel.");
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
#endif
|
||||
case 3:
|
||||
q = lookup_xprison_v3(q, (char *)p + len, &id, jailname);
|
||||
break;
|
||||
default:
|
||||
errx(1, "Prison unknown. Kernel/userland out of sync?");
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
}
|
||||
/* Possible match. */
|
||||
if (id > 0) {
|
||||
/* Do we have a jail ID to match as well? */
|
||||
if (jid > 0) {
|
||||
if (jid == id) {
|
||||
xid = id;
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
xid = id;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(p);
|
||||
|
||||
if (count != 1)
|
||||
errx(1, "Could not uniquely identify the jail.");
|
||||
|
||||
return (xid);
|
||||
}
|
||||
|
||||
#define GET_USER_INFO do { \
|
||||
pwd = getpwnam(username); \
|
||||
@ -68,13 +220,18 @@ main(int argc, char *argv[])
|
||||
login_cap_t *lcap = NULL;
|
||||
struct passwd *pwd = NULL;
|
||||
gid_t groups[NGROUPS];
|
||||
int ch, ngroups, uflag, Uflag, hflag;
|
||||
char *username;
|
||||
ch = uflag = Uflag = hflag = 0;
|
||||
username = NULL;
|
||||
int ch, ngroups, uflag, Uflag;
|
||||
char *jailname, *username;
|
||||
|
||||
while ((ch = getopt(argc, argv, "u:U:h")) != -1) {
|
||||
ch = uflag = Uflag = 0;
|
||||
jailname = username = NULL;
|
||||
jid = -1;
|
||||
|
||||
while ((ch = getopt(argc, argv, "i:n:u:U:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
jailname = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
username = optarg;
|
||||
uflag = 1;
|
||||
@ -83,9 +240,6 @@ main(int argc, char *argv[])
|
||||
username = optarg;
|
||||
Uflag = 1;
|
||||
break;
|
||||
case 'h':
|
||||
hflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@ -94,15 +248,22 @@ main(int argc, char *argv[])
|
||||
argv += optind;
|
||||
if (argc < 2)
|
||||
usage();
|
||||
if (strlen(argv[0]) > 0) {
|
||||
jid = (int)strtol(argv[0], NULL, 10);
|
||||
if (errno)
|
||||
err(1, "Unable to parse jail ID.");
|
||||
}
|
||||
if (jid <= 0 && jailname == NULL) {
|
||||
fprintf(stderr, "Neither jail ID nor jail name given.\n");
|
||||
usage();
|
||||
}
|
||||
if (uflag && Uflag)
|
||||
usage();
|
||||
if (uflag)
|
||||
GET_USER_INFO;
|
||||
if (hflag) {
|
||||
if ((jid = addr2jid(argv[0])) == 0)
|
||||
errx(1, "jail_attach(): Cannot convert %s to jid", argv[0]);
|
||||
} else
|
||||
jid = (int)strtol(argv[0], NULL, 10);
|
||||
jid = lookup_jail(jid, jailname);
|
||||
if (jid <= 0)
|
||||
errx(1, "Cannot identify jail.");
|
||||
if (jail_attach(jid) == -1)
|
||||
err(1, "jail_attach(): %d", jid);
|
||||
if (chdir("/") == -1)
|
||||
@ -130,54 +291,6 @@ usage(void)
|
||||
|
||||
fprintf(stderr, "%s%s\n",
|
||||
"usage: jexec [-u username | -U username]",
|
||||
" [-h hostname | -h ip-number | jid] command ...");
|
||||
" [-n jailname] jid command ...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
addr2jid(const char *addr)
|
||||
{
|
||||
struct xprison *sxp, *xp;
|
||||
struct in_addr in;
|
||||
size_t i, len;
|
||||
int jid, cnt;
|
||||
jid = cnt = 0;
|
||||
|
||||
if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (len <= 0)
|
||||
err(1, "sysctlbyname(): len <=0");
|
||||
sxp = xp = malloc(len);
|
||||
if (sxp == NULL)
|
||||
err(1, "malloc()");
|
||||
if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) {
|
||||
if (errno == ENOMEM) {
|
||||
free(sxp);
|
||||
sxp = NULL;
|
||||
continue;
|
||||
}
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (sxp == NULL)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
if (len < sizeof(*xp) || len % sizeof(*xp) ||
|
||||
xp->pr_version != XPRISON_VERSION)
|
||||
errx(1, "Kernel and userland out of sync");
|
||||
for (i = 0; i < len / sizeof(*xp); i++) {
|
||||
in.s_addr = ntohl(xp->pr_ip);
|
||||
if ((strcmp(inet_ntoa(in), addr) == 0) ||
|
||||
(strcmp(xp->pr_host, addr) == 0)) {
|
||||
jid = xp->pr_id;
|
||||
cnt++;
|
||||
}
|
||||
xp++;
|
||||
}
|
||||
free(sxp);
|
||||
if (cnt == 1)
|
||||
return (jid);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
@ -4,4 +4,6 @@ PROG= jls
|
||||
MAN= jls.8
|
||||
WARNS?= 6
|
||||
|
||||
CFLAGS+= -DSUPPORT_OLD_XPRISON
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -25,20 +25,44 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 8, 2003
|
||||
.Dd November 29, 2008
|
||||
.Dt JLS 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm jls
|
||||
.Nd "list active jails"
|
||||
.Nd "list jails"
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl av
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility lists all active jails.
|
||||
Each jail is represented by one row which contains the following columns:
|
||||
jail identifier (JID), IP address, hostname, and path.
|
||||
utility lists all jails.
|
||||
By default only active jails are listed.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width ".Fl a"
|
||||
.It Fl a
|
||||
Show jails in all states, not only active ones.
|
||||
.It Fl v
|
||||
Show more verbose information.
|
||||
This also lists cpusets, jail state, multi-IP, etc. instead of the
|
||||
classic single-IP jail output.
|
||||
.El
|
||||
.Pp
|
||||
Each jail is represented by rows which, depending on
|
||||
.Fl v ,
|
||||
contain the following columns:
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
jail identifier (JID), hostname and path
|
||||
.It
|
||||
jail state and name
|
||||
.It
|
||||
jail cpuset
|
||||
.It
|
||||
followed by one IP adddress per line.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr jail 2 ,
|
||||
.Xr jail 8 ,
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
|
||||
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -27,57 +28,216 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FLAG_A 0x00001
|
||||
#define FLAG_V 0x00002
|
||||
|
||||
#ifdef SUPPORT_OLD_XPRISON
|
||||
static
|
||||
char *print_xprison_v1(void *p, char *end)
|
||||
{
|
||||
struct xprison_v1 *xp;
|
||||
struct in_addr in;
|
||||
|
||||
if ((char *)p + sizeof(struct xprison_v1) > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
|
||||
xp = (struct xprison_v1 *)p;
|
||||
printf("%6d %-29.29s %.74s\n",
|
||||
xp->pr_id, xp->pr_host, xp->pr_path);
|
||||
|
||||
/* We are not printing an empty line here for state and name. */
|
||||
/* We are not printing an empty line here for cpusetid. */
|
||||
|
||||
/* IPv4 address. */
|
||||
in.s_addr = htonl(xp->pr_ip);
|
||||
printf("%6s %-15.15s\n", "", inet_ntoa(in));
|
||||
|
||||
return ((char *)(xp + 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
char *print_xprison_v3(void *p, char *end, unsigned flags)
|
||||
{
|
||||
struct xprison *xp;
|
||||
struct in_addr *iap, in;
|
||||
struct in6_addr *ia6p;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
const char *state;
|
||||
char *q;
|
||||
uint32_t i;
|
||||
|
||||
if ((char *)p + sizeof(struct xprison) > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
xp = (struct xprison *)p;
|
||||
|
||||
if (xp->pr_state < 0 || xp->pr_state > (int)
|
||||
((sizeof(prison_states) / sizeof(struct prison_state))))
|
||||
state = "(bogus)";
|
||||
else
|
||||
state = prison_states[xp->pr_state].state_name;
|
||||
|
||||
/* See if we should print non-ACTIVE jails. No? */
|
||||
if ((flags & FLAG_A) == 0 && strcmp(state, "ALIVE")) {
|
||||
q = (char *)(xp + 1);
|
||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
||||
if (q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
||||
if (q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
return (q);
|
||||
}
|
||||
|
||||
printf("%6d %-29.29s %.74s\n",
|
||||
xp->pr_id, xp->pr_host, xp->pr_path);
|
||||
|
||||
/* Jail state and name. */
|
||||
if (flags & FLAG_V)
|
||||
printf("%6s %-29.29s %.74s\n",
|
||||
"", (xp->pr_name != NULL) ? xp->pr_name : "", state);
|
||||
|
||||
/* cpusetid. */
|
||||
if (flags & FLAG_V)
|
||||
printf("%6s %-6d\n",
|
||||
"", xp->pr_cpusetid);
|
||||
|
||||
q = (char *)(xp + 1);
|
||||
/* IPv4 addresses. */
|
||||
iap = (struct in_addr *)(void *)q;
|
||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
||||
if (q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
for (i = 0; i < xp->pr_ip4s; i++) {
|
||||
if (i == 0 || flags & FLAG_V) {
|
||||
in.s_addr = iap[i].s_addr;
|
||||
printf("%6s %-15.15s\n", "", inet_ntoa(in));
|
||||
}
|
||||
}
|
||||
/* IPv6 addresses. */
|
||||
ia6p = (struct in6_addr *)(void *)q;
|
||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
||||
if (q > end)
|
||||
errx(1, "Invalid length for jail");
|
||||
for (i = 0; i < xp->pr_ip6s; i++) {
|
||||
if (flags & FLAG_V) {
|
||||
inet_ntop(AF_INET6, &ia6p[i], buf, sizeof(buf));
|
||||
printf("%6s %s\n", "", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return (q);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: jls [-av]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct xprison *sxp, *xp;
|
||||
struct in_addr in;
|
||||
size_t i, len;
|
||||
int ch, version;
|
||||
unsigned flags;
|
||||
size_t i, j, len;
|
||||
void *p, *q;
|
||||
|
||||
flags = 0;
|
||||
while ((ch = getopt(argc, argv, "av")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
flags |= FLAG_A;
|
||||
break;
|
||||
case 'v':
|
||||
flags |= FLAG_V;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
|
||||
j = len;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (len <= 0)
|
||||
exit(0);
|
||||
sxp = xp = malloc(len);
|
||||
if (sxp == NULL)
|
||||
p = q = malloc(len);
|
||||
if (p == NULL)
|
||||
err(1, "malloc()");
|
||||
|
||||
if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) {
|
||||
if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
|
||||
if (errno == ENOMEM) {
|
||||
free(sxp);
|
||||
sxp = NULL;
|
||||
free(p);
|
||||
p = NULL;
|
||||
len += j;
|
||||
continue;
|
||||
}
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (sxp == NULL)
|
||||
if (p == NULL)
|
||||
err(1, "sysctlbyname(): security.jail.list");
|
||||
if (len < sizeof(*xp) || len % sizeof(*xp) ||
|
||||
xp->pr_version != XPRISON_VERSION)
|
||||
errx(1, "Kernel and userland out of sync");
|
||||
if (len < sizeof(int))
|
||||
errx(1, "This is no prison. Kernel and userland out of sync?");
|
||||
version = *(int *)p;
|
||||
if (version > XPRISON_VERSION)
|
||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
||||
|
||||
printf(" JID IP Address Hostname Path\n");
|
||||
for (i = 0; i < len / sizeof(*xp); i++) {
|
||||
in.s_addr = ntohl(xp->pr_ip);
|
||||
printf("%6d %-15.15s %-29.29s %.74s\n",
|
||||
xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
|
||||
xp++;
|
||||
printf(" JID Hostname Path\n");
|
||||
if (flags & FLAG_V) {
|
||||
printf(" Name State\n");
|
||||
printf(" CPUSetID\n");
|
||||
}
|
||||
free(sxp);
|
||||
printf(" IP Address(es)\n");
|
||||
for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
|
||||
version = *(int *)q;
|
||||
if (version > XPRISON_VERSION)
|
||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
||||
switch (version) {
|
||||
#ifdef SUPPORT_OLD_XPRISON
|
||||
case 1:
|
||||
q = print_xprison_v1(q, (char *)p + len);
|
||||
break;
|
||||
case 2:
|
||||
errx(1, "Version 2 was used by multi-IPv4 jail "
|
||||
"implementations that never made it into the "
|
||||
"official kernel.");
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
#endif
|
||||
case 3:
|
||||
q = print_xprison_v3(q, (char *)p + len, flags);
|
||||
break;
|
||||
default:
|
||||
errx(1, "Prison unknown. Kernel/userland out of sync?");
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(p);
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user