Remove the interim vimage containers, struct vimage and struct procg,

and the ioctl-based interface that supported them.

Approved by:	re (kib), bz (mentor)
This commit is contained in:
Jamie Gritton 2009-07-17 14:48:21 +00:00
parent 597df30e62
commit 7afcbc18b3
13 changed files with 124 additions and 564 deletions

View File

@ -74,7 +74,6 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/cpuset.h>
#include <sys/vimage.h>
#include <machine/cpu.h>
@ -454,12 +453,6 @@ proc0_init(void *dummy __unused)
p->p_ucred->cr_uidinfo = uifind(0);
p->p_ucred->cr_ruidinfo = uifind(0);
p->p_ucred->cr_prison = &prison0;
#ifdef VIMAGE
KASSERT(LIST_FIRST(&vimage_head) != NULL, ("vimage_head empty"));
P_TO_VIMAGE(p) = LIST_FIRST(&vimage_head); /* set ucred->cr_vimage */
refcount_acquire(&P_TO_VIMAGE(p)->vi_ucredrefc);
LIST_FIRST(&vprocg_head)->nprocs++;
#endif
#ifdef AUDIT
audit_cred_kproc0(p->p_ucred);
#endif

View File

@ -69,7 +69,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sdt.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/vimage.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
@ -687,7 +686,6 @@ static void
proc_reap(struct thread *td, struct proc *p, int *status, int options,
struct rusage *rusage)
{
INIT_VPROCG(P_TO_VPROCG(p));
struct proc *q, *t;
sx_assert(&proctree_lock, SA_XLOCKED);
@ -791,9 +789,6 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options,
uma_zfree(proc_zone, p);
sx_xlock(&allproc_lock);
nprocs--;
#ifdef VIMAGE
vprocg->nprocs--;
#endif
sx_xunlock(&allproc_lock);
}

View File

@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sdt.h>
#include <sys/sx.h>
#include <sys/signalvar.h>
#include <sys/vimage.h>
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
@ -363,9 +362,6 @@ fork1(td, flags, pages, procp)
* are hard-limits as to the number of processes that can run.
*/
nprocs++;
#ifdef VIMAGE
P_TO_VPROCG(p1)->nprocs++;
#endif
/*
* Find an unused process ID. We remember a range of unused IDs

View File

@ -3243,10 +3243,6 @@ int
prison_check(struct ucred *cred1, struct ucred *cred2)
{
#ifdef VIMAGE
if (cred2->cr_vimage->v_procg != cred1->cr_vimage->v_procg)
return (ESRCH);
#endif
return ((cred1->cr_prison == cred2->cr_prison ||
prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH);
}

View File

@ -992,12 +992,6 @@ kern_kldload(struct thread *td, const char *file, int *fileid)
if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
return (error);
#ifdef VIMAGE
/* Only the default vimage is permitted to kldload modules. */
if (!IS_DEFAULT_VIMAGE(TD_TO_VIMAGE(td)))
return (EPERM);
#endif
/*
* It is possible that kldloaded module will attach a new ifnet,
* so vnet context must be set when this ocurs.
@ -1069,12 +1063,6 @@ kern_kldunload(struct thread *td, int fileid, int flags)
if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0)
return (error);
#ifdef VIMAGE
/* Only the default vimage is permitted to kldunload modules. */
if (!IS_DEFAULT_VIMAGE(TD_TO_VIMAGE(td)))
return (EPERM);
#endif
CURVNET_SET(TD_TO_VNET(td));
KLD_LOCK();
lf = linker_find_file_by_id(fileid);

View File

@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$");
#include <sys/socketvar.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/vimage.h>
#if defined(INET) || defined(INET6)
#include <netinet/in.h>
@ -1762,11 +1761,7 @@ p_canwait(struct thread *td, struct proc *p)
KASSERT(td == curthread, ("%s: td not curthread", __func__));
PROC_LOCK_ASSERT(p, MA_OWNED);
if (
#ifdef VIMAGE /* XXX temporary until struct vimage goes away */
!vi_child_of(TD_TO_VIMAGE(td), P_TO_VIMAGE(p)) &&
#endif
(error = prison_check(td->td_ucred, p->p_ucred)))
if ((error = prison_check(td->td_ucred, p->p_ucred)))
return (error);
#ifdef MAC
if ((error = mac_proc_check_wait(td->td_ucred, p)))
@ -1836,11 +1831,6 @@ crfree(struct ucred *cr)
*/
if (cr->cr_prison != NULL)
prison_free(cr->cr_prison);
#ifdef VIMAGE
/* XXX TODO: find out why and when cr_vimage can be NULL here! */
if (cr->cr_vimage != NULL)
refcount_release(&cr->cr_vimage->vi_ucredrefc);
#endif
#ifdef AUDIT
audit_cred_destroy(cr);
#endif
@ -1877,10 +1867,6 @@ crcopy(struct ucred *dest, struct ucred *src)
uihold(dest->cr_uidinfo);
uihold(dest->cr_ruidinfo);
prison_hold(dest->cr_prison);
#ifdef VIMAGE
KASSERT(src->cr_vimage != NULL, ("cr_vimage == NULL"));
refcount_acquire(&dest->cr_vimage->vi_ucredrefc);
#endif
#ifdef AUDIT
audit_cred_copy(src, dest);
#endif

View File

@ -36,14 +36,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sx.h>
#include <sys/priv.h>
#include <sys/refcount.h>
#include <sys/vimage.h>
#ifdef DDB
#include <ddb/ddb.h>
@ -53,9 +50,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
MALLOC_DEFINE(M_VIMAGE, "vimage", "vimage resource container");
MALLOC_DEFINE(M_VNET, "vnet", "network stack control block");
MALLOC_DEFINE(M_VPROCG, "vprocg", "process group control block");
static TAILQ_HEAD(vnet_modlink_head, vnet_modlink) vnet_modlink_head;
static TAILQ_HEAD(vnet_modpending_head, vnet_modlink) vnet_modpending_head;
@ -63,12 +58,6 @@ static void vnet_mod_complete_registration(struct vnet_modlink *);
static int vnet_mod_constructor(struct vnet_modlink *);
static int vnet_mod_destructor(struct vnet_modlink *);
static struct vimage *vi_alloc(struct vimage *, char *);
static int vi_destroy(struct vimage *);
static struct vimage *vimage_get_next(struct vimage *, struct vimage *, int);
static void vimage_relative_name(struct vimage *, struct vimage *,
char *, int);
#define VNET_LIST_WLOCK() \
mtx_lock(&vnet_list_refc_mtx); \
while (vnet_list_refc != 0) \
@ -77,82 +66,45 @@ static void vimage_relative_name(struct vimage *, struct vimage *,
#define VNET_LIST_WUNLOCK() \
mtx_unlock(&vnet_list_refc_mtx);
struct vimage_list_head vimage_head;
struct vnet_list_head vnet_head;
struct vprocg_list_head vprocg_head;
struct vprocg vprocg_0;
struct cv vnet_list_condvar;
struct mtx vnet_list_refc_mtx;
int vnet_list_refc = 0;
static u_int last_vi_id = 0;
static u_int last_vprocg_id = 0;
struct vnet *vnet0;
/*
* Move an ifnet to or from another vnet, specified by the jail id. If a
* vi_req is passed in, it is used to find the interface and a vimage
* containing the vnet (a vimage name of ".." stands for the parent vnet).
* Move an ifnet to or from another vnet, specified by the jail id.
*/
int
vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid,
struct vi_req *vi_req)
vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
{
struct ifnet *t_ifp;
struct prison *pr;
struct vimage *new_vip, *my_vip;
struct vnet *new_vnet;
int error;
if (vi_req != NULL) {
/* SIOCSIFVIMAGE */
pr = NULL;
/* Check for API / ABI version mismatch. */
if (vi_req->vi_api_cookie != VI_API_COOKIE)
return (EDOOFUS);
/* Find the target vnet. */
my_vip = TD_TO_VIMAGE(td);
if (strcmp(vi_req->vi_name, "..") == 0) {
if (IS_DEFAULT_VIMAGE(my_vip))
return (ENXIO);
new_vnet = my_vip->vi_parent->v_net;
} else {
new_vip = vimage_by_name(my_vip, vi_req->vi_name);
if (new_vip == NULL)
return (ENXIO);
new_vnet = new_vip->v_net;
}
/* Try to find the target ifnet by name. */
ifname = vi_req->vi_if_xname;
ifp = ifunit(ifname);
if (ifp == NULL)
return (ENXIO);
sx_slock(&allprison_lock);
pr = prison_find_child(td->td_ucred->cr_prison, jid);
sx_sunlock(&allprison_lock);
if (pr == NULL)
return (ENXIO);
prison_hold_locked(pr);
mtx_unlock(&pr->pr_mtx);
if (ifp != NULL) {
/* SIOCSIFVNET */
new_vnet = pr->pr_vnet;
} else {
sx_slock(&allprison_lock);
pr = prison_find_child(td->td_ucred->cr_prison, jid);
sx_sunlock(&allprison_lock);
if (pr == NULL)
/* SIOCSIFRVNET */
new_vnet = TD_TO_VNET(td);
CURVNET_SET(pr->pr_vnet);
ifp = ifunit(ifname);
CURVNET_RESTORE();
if (ifp == NULL) {
prison_free(pr);
return (ENXIO);
prison_hold_locked(pr);
mtx_unlock(&pr->pr_mtx);
if (ifp != NULL) {
/* SIOCSIFVNET */
new_vnet = pr->pr_vnet;
} else {
/* SIOCSIFRVNET */
new_vnet = TD_TO_VNET(td);
CURVNET_SET(pr->pr_vnet);
ifp = ifunit(ifname);
CURVNET_RESTORE();
if (ifp == NULL) {
prison_free(pr);
return (ENXIO);
}
}
}
@ -175,215 +127,10 @@ vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid,
sprintf(ifname, "%s", ifp->if_xname);
}
}
if (pr != NULL)
prison_free(pr);
prison_free(pr);
return (error);
}
/*
* Interim userspace interface - will be replaced by jail soon.
*/
int
vi_td_ioctl(u_long cmd, struct vi_req *vi_req, struct thread *td)
{
int error = 0;
struct vimage *vip = TD_TO_VIMAGE(td);
struct vimage *vip_r = NULL;
/* Check for API / ABI version mismatch. */
if (vi_req->vi_api_cookie != VI_API_COOKIE)
return (EDOOFUS);
error = priv_check(td, PRIV_REBOOT); /* XXX temp. priv abuse */
if (error)
return (error);
vip_r = vimage_by_name(vip, vi_req->vi_name);
if (vip_r == NULL && !(vi_req->vi_req_action & VI_CREATE))
return (ESRCH);
if (vip_r != NULL && vi_req->vi_req_action & VI_CREATE)
return (EADDRINUSE);
if (vi_req->vi_req_action == VI_GETNEXT) {
vip_r = vimage_get_next(vip, vip_r, 0);
if (vip_r == NULL)
return (ESRCH);
}
if (vi_req->vi_req_action == VI_GETNEXT_RECURSE) {
vip_r = vimage_get_next(vip, vip_r, 1);
if (vip_r == NULL)
return (ESRCH);
}
if (vip_r && !vi_child_of(vip, vip_r) && /* XXX delete the rest? */
vi_req->vi_req_action != VI_GET &&
vi_req->vi_req_action != VI_GETNEXT)
return (EPERM);
switch (cmd) {
case SIOCGPVIMAGE:
vimage_relative_name(vip, vip_r, vi_req->vi_name,
sizeof (vi_req->vi_name));
vi_req->vi_proc_count = vip_r->v_procg->nprocs;
vi_req->vi_if_count = vip_r->v_net->ifcnt;
vi_req->vi_sock_count = vip_r->v_net->sockcnt;
break;
case SIOCSPVIMAGE:
if (vi_req->vi_req_action == VI_DESTROY) {
error = vi_destroy(vip_r);
break;
}
if (vi_req->vi_req_action == VI_SWITCHTO) {
struct proc *p = td->td_proc;
struct ucred *oldcred, *newcred;
/*
* XXX priv_check()?
* XXX allow only a single td per proc here?
*/
newcred = crget();
PROC_LOCK(p);
oldcred = p->p_ucred;
setsugid(p);
crcopy(newcred, oldcred);
refcount_release(&newcred->cr_vimage->vi_ucredrefc);
newcred->cr_vimage = vip_r;
refcount_acquire(&newcred->cr_vimage->vi_ucredrefc);
p->p_ucred = newcred;
PROC_UNLOCK(p);
sx_xlock(&allproc_lock);
oldcred->cr_vimage->v_procg->nprocs--;
refcount_release(&oldcred->cr_vimage->vi_ucredrefc);
P_TO_VPROCG(p)->nprocs++;
sx_xunlock(&allproc_lock);
crfree(oldcred);
break;
}
if (vi_req->vi_req_action & VI_CREATE) {
char *dotpos;
dotpos = strrchr(vi_req->vi_name, '.');
if (dotpos != NULL) {
*dotpos = 0;
vip = vimage_by_name(vip, vi_req->vi_name);
if (vip == NULL)
return (ESRCH);
dotpos++;
vip_r = vi_alloc(vip, dotpos);
} else
vip_r = vi_alloc(vip, vi_req->vi_name);
if (vip_r == NULL)
return (ENOMEM);
}
}
return (error);
}
int
vi_child_of(struct vimage *parent, struct vimage *child)
{
if (child == parent)
return (0);
for (; child; child = child->vi_parent)
if (child == parent)
return (1);
return (0);
}
struct vimage *
vimage_by_name(struct vimage *top, char *name)
{
struct vimage *vip;
char *next_name;
int namelen;
next_name = strchr(name, '.');
if (next_name != NULL) {
namelen = next_name - name;
next_name++;
if (namelen == 0) {
if (strlen(next_name) == 0)
return (top); /* '.' == this vimage */
else
return (NULL);
}
} else
namelen = strlen(name);
if (namelen == 0)
return (NULL);
LIST_FOREACH(vip, &top->vi_child_head, vi_sibling) {
if (strlen(vip->vi_name) == namelen &&
strncmp(name, vip->vi_name, namelen) == 0) {
if (next_name != NULL)
return (vimage_by_name(vip, next_name));
else
return (vip);
}
}
return (NULL);
}
static void
vimage_relative_name(struct vimage *top, struct vimage *where,
char *buffer, int bufflen)
{
int used = 1;
if (where == top) {
sprintf(buffer, ".");
return;
} else
*buffer = 0;
do {
int namelen = strlen(where->vi_name);
if (namelen + used + 1 >= bufflen)
panic("buffer overflow");
if (used > 1) {
bcopy(buffer, &buffer[namelen + 1], used);
buffer[namelen] = '.';
used++;
} else
bcopy(buffer, &buffer[namelen], used);
bcopy(where->vi_name, buffer, namelen);
used += namelen;
where = where->vi_parent;
} while (where != top);
}
static struct vimage *
vimage_get_next(struct vimage *top, struct vimage *where, int recurse)
{
struct vimage *next;
if (recurse) {
/* Try to go deeper in the hierarchy */
next = LIST_FIRST(&where->vi_child_head);
if (next != NULL)
return (next);
}
do {
/* Try to find next sibling */
next = LIST_NEXT(where, vi_sibling);
if (!recurse || next != NULL)
return (next);
/* Nothing left on this level, go one level up */
where = where->vi_parent;
} while (where != top->vi_parent);
/* Nothing left to be visited, we are done */
return (NULL);
}
/*
* Kernel interfaces and handlers.
@ -409,7 +156,7 @@ vnet_mod_register_multi(const struct vnet_modinfo *vmi, void *iarg,
if (vml_iter != NULL)
panic("registering an already registered vnet module: %s",
vml_iter->vml_modinfo->vmi_name);
vml = malloc(sizeof(struct vnet_modlink), M_VIMAGE, M_NOWAIT);
vml = malloc(sizeof(struct vnet_modlink), M_VNET, M_NOWAIT);
/*
* XXX we support only statically assigned module IDs at the time.
@ -513,7 +260,7 @@ vnet_mod_deregister_multi(const struct vnet_modinfo *vmi, void *iarg,
}
TAILQ_REMOVE(&vnet_modlink_head, vml, vml_mod_le);
free(vml, M_VIMAGE);
free(vml, M_VNET);
}
static int
@ -625,75 +372,6 @@ vnet_foreach(void (*vnet_foreach_fn)(struct vnet *, void *), void *arg)
VNET_LIST_RUNLOCK();
}
static struct vimage *
vi_alloc(struct vimage *parent, char *name)
{
struct vimage *vip;
struct vprocg *vprocg;
vip = malloc(sizeof(struct vimage), M_VIMAGE, M_NOWAIT | M_ZERO);
if (vip == NULL)
panic("vi_alloc: malloc failed for vimage \"%s\"\n", name);
vip->vi_id = last_vi_id++;
LIST_INIT(&vip->vi_child_head);
sprintf(vip->vi_name, "%s", name);
vip->vi_parent = parent;
/* XXX locking */
if (parent != NULL)
LIST_INSERT_HEAD(&parent->vi_child_head, vip, vi_sibling);
else if (!LIST_EMPTY(&vimage_head))
panic("there can be only one default vimage!");
LIST_INSERT_HEAD(&vimage_head, vip, vi_le);
vip->v_net = vnet_alloc();
vprocg = malloc(sizeof(struct vprocg), M_VPROCG, M_NOWAIT | M_ZERO);
if (vprocg == NULL)
panic("vi_alloc: malloc failed for vprocg \"%s\"\n", name);
vip->v_procg = vprocg;
vprocg->vprocg_id = last_vprocg_id++;
/* XXX locking */
LIST_INSERT_HEAD(&vprocg_head, vprocg, vprocg_le);
return (vip);
}
/*
* Destroy a vnet - unlink all linked lists, hashtables etc., free all
* the memory, stop all the timers...
*/
static int
vi_destroy(struct vimage *vip)
{
struct vprocg *vprocg = vip->v_procg;
/* XXX Beware of races -> more locking to be done... */
if (!LIST_EMPTY(&vip->vi_child_head))
return (EBUSY);
if (vprocg->nprocs != 0)
return (EBUSY);
#ifdef INVARIANTS
if (vip->vi_ucredrefc != 0)
printf("vi_destroy: %s ucredrefc %d\n",
vip->vi_name, vip->vi_ucredrefc);
#endif
/* Point with no return - cleanup MUST succeed! */
vnet_destroy(vip->v_net);
LIST_REMOVE(vip, vi_le);
LIST_REMOVE(vip, vi_sibling);
LIST_REMOVE(vprocg, vprocg_le);
free(vprocg, M_VPROCG);
free(vip, M_VIMAGE);
return (0);
}
static void
vi_init(void *unused)
{
@ -701,22 +379,17 @@ vi_init(void *unused)
TAILQ_INIT(&vnet_modlink_head);
TAILQ_INIT(&vnet_modpending_head);
LIST_INIT(&vimage_head);
LIST_INIT(&vprocg_head);
LIST_INIT(&vnet_head);
mtx_init(&vnet_list_refc_mtx, "vnet_list_refc_mtx", NULL, MTX_DEF);
cv_init(&vnet_list_condvar, "vnet_list_condvar");
/* Default image has no parent and no name. */
vi_alloc(NULL, "");
/*
* We MUST clear curvnet in vi_init_done() before going SMP,
* otherwise CURVNET_SET() macros would scream about unnecessary
* curvnet recursions.
*/
curvnet = prison0.pr_vnet = vnet0 = LIST_FIRST(&vnet_head);
curvnet = prison0.pr_vnet = vnet0 = vnet_alloc();
}
static void

View File

@ -2008,7 +2008,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
error = priv_check(td, PRIV_NET_SETIFVNET);
if (error)
return (error);
error = vi_if_move(td, ifp, ifr->ifr_name, ifr->ifr_jid, NULL);
error = vi_if_move(td, ifp, ifr->ifr_name, ifr->ifr_jid);
break;
#endif
@ -2202,20 +2202,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
error = priv_check(td, PRIV_NET_SETIFVNET);
if (error)
return (error);
return (vi_if_move(td, NULL, ifr->ifr_name, ifr->ifr_jid,
NULL));
/*
* XXX vnet creation will be implemented through the new jail
* framework - this is just a temporary hack for testing the
* vnet create / destroy mechanisms.
*/
case SIOCSIFVIMAGE:
error = vi_if_move(td, NULL, NULL, 0, (struct vi_req *) data);
return (error);
case SIOCSPVIMAGE:
case SIOCGPVIMAGE:
error = vi_td_ioctl(cmd, (struct vi_req *) data, td);
return (error);
return (vi_if_move(td, NULL, ifr->ifr_name, ifr->ifr_jid));
#endif
case SIOCIFCREATE:
case SIOCIFCREATE2:

View File

@ -111,10 +111,6 @@
#define SIOCSIFVNET _IOWR('i', 90, struct ifreq) /* move IF jail/vnet */
#define SIOCSIFRVNET _IOWR('i', 91, struct ifreq) /* reclaim vnet IF */
#define SIOCSPVIMAGE _IOW('i', 101, struct vi_req) /* set proc vimage */
#define SIOCGPVIMAGE _IOWR('i', 102, struct vi_req) /* get proc vimage */
#define SIOCSIFVIMAGE _IOWR('i', 103, struct vi_req) /* set ifc vi/net */
#define SIOCSDRVSPEC _IOW('i', 123, struct ifdrv) /* set driver-specific
parameters */
#define SIOCGDRVSPEC _IOWR('i', 123, struct ifdrv) /* get driver-specific

View File

@ -54,9 +54,9 @@ struct ucred {
struct uidinfo *cr_uidinfo; /* per euid resource consumption */
struct uidinfo *cr_ruidinfo; /* per ruid resource consumption */
struct prison *cr_prison; /* jail(2) */
struct vimage *cr_vimage; /* vimage */
void *cr_pspare; /* general use */
u_int cr_flags; /* credential flags */
void *cr_pspare[2]; /* general use 2 */
void *cr_pspare2[2]; /* general use 2 */
#define cr_endcopy cr_label
struct label *cr_label; /* MAC label */
struct auditinfo_addr cr_audit; /* Audit properties. */

View File

@ -36,42 +36,14 @@
#include <sys/proc.h>
#include <sys/queue.h>
/* Interim userspace API. */
struct vi_req {
int vi_api_cookie; /* Catch API mismatch. */
int vi_req_action; /* What to do with this request? */
u_short vi_proc_count; /* Current number of processes. */
int vi_if_count; /* Current number of ifnets. */
int vi_sock_count;
char vi_name[MAXPATHLEN];
char vi_if_xname[MAXPATHLEN]; /* XXX should be IFNAMSIZ */
};
#define VI_CREATE 0x00000001
#define VI_DESTROY 0x00000002
#define VI_SWITCHTO 0x00000008
#define VI_IFACE 0x00000010
#define VI_GET 0x00000100
#define VI_GETNEXT 0x00000200
#define VI_GETNEXT_RECURSE 0x00000300
#define VI_API_VERSION 1 /* Bump on struct changes. */
#define VI_API_COOKIE ((sizeof(struct vi_req) << 16) | VI_API_VERSION)
#ifdef _KERNEL
#ifdef INVARIANTS
#define VNET_DEBUG
#endif
struct vimage;
struct vprocg;
struct vnet;
struct vi_req;
struct ifnet;
struct kld_sym_lookup;
struct thread;
typedef int vnet_attach_fn(const void *);
typedef int vnet_detach_fn(const void *);
@ -128,16 +100,7 @@ struct vnet_modlink {
#define VNET_MOD_DYNAMIC_START 32
#define VNET_MOD_MAX 64
/* Major module IDs for vimage sysctl virtualization. */
#define V_GLOBAL 0 /* global variable - no indirection */
#define V_NET 1
#define V_PROCG 2
int vi_td_ioctl(u_long, struct vi_req *, struct thread *);
int vi_if_move(struct thread *, struct ifnet *, char *, int,
struct vi_req *);
int vi_child_of(struct vimage *, struct vimage *);
struct vimage *vimage_by_name(struct vimage *, char *);
int vi_if_move(struct thread *, struct ifnet *, char *, int);
void vnet_mod_register(const struct vnet_modinfo *);
void vnet_mod_register_multi(const struct vnet_modinfo *, void *, char *);
void vnet_mod_deregister(const struct vnet_modinfo *);
@ -149,18 +112,6 @@ void vnet_foreach(void (*vnet_foreach_fn)(struct vnet *, void *),
#endif /* VIMAGE */
struct vimage {
LIST_ENTRY(vimage) vi_le; /* all vimage list */
LIST_ENTRY(vimage) vi_sibling; /* vimages with same parent */
LIST_HEAD(, vimage) vi_child_head; /* direct offspring list */
struct vimage *vi_parent; /* ptr to parent vimage */
u_int vi_id; /* ID num */
volatile u_int vi_ucredrefc; /* # of ucreds pointing to us */
char vi_name[MAXHOSTNAMELEN];
struct vnet *v_net;
struct vprocg *v_procg;
};
struct vnet {
LIST_ENTRY(vnet) vnet_le; /* all vnets list */
u_int vnet_magic_n;
@ -170,19 +121,6 @@ struct vnet {
uintptr_t vnet_data_base;
};
struct vprocg {
LIST_ENTRY(vprocg) vprocg_le;
u_int vprocg_id; /* ID num */
u_int nprocs;
};
#ifdef VIMAGE
LIST_HEAD(vimage_list_head, vimage);
extern struct vimage_list_head vimage_head;
#else /* !VIMAGE */
extern struct vprocg vprocg_0;
#endif /* VIMAGE */
#define curvnet curthread->td_vnet
#define VNET_MAGIC_N 0x3e0d8f29
@ -249,39 +187,19 @@ extern struct vnet *vnet0;
#endif
#ifdef VIMAGE
LIST_HEAD(vprocg_list_head, vprocg);
extern struct vprocg_list_head vprocg_head;
#define INIT_VPROCG(arg) struct vprocg *vprocg = (arg);
#else
#define INIT_VPROCG(arg)
#endif
#ifdef VIMAGE
#define IS_DEFAULT_VIMAGE(arg) ((arg)->vi_id == 0)
#define IS_DEFAULT_VNET(arg) ((arg) == vnet0)
#else
#define IS_DEFAULT_VIMAGE(arg) 1
#define IS_DEFAULT_VNET(arg) 1
#endif
#ifdef VIMAGE
#define CRED_TO_VNET(cr) \
(IS_DEFAULT_VIMAGE((cr)->cr_vimage) ? (cr)->cr_prison->pr_vnet \
: (cr)->cr_vimage->v_net)
#define TD_TO_VIMAGE(td) (td)->td_ucred->cr_vimage
#define CRED_TO_VNET(cr) (cr)->cr_prison->pr_vnet
#define TD_TO_VNET(td) CRED_TO_VNET((td)->td_ucred)
#define TD_TO_VPROCG(td) (td)->td_ucred->cr_vimage->v_procg
#define P_TO_VIMAGE(p) (p)->p_ucred->cr_vimage
#define P_TO_VNET(p) CRED_TO_VNET((p)->p_ucred)
#define P_TO_VPROCG(p) (p)->p_ucred->cr_vimage->v_procg
#else /* !VIMAGE */
#define CRED_TO_VNET(cr) NULL
#define TD_TO_VIMAGE(td) NULL
#define TD_TO_VNET(td) NULL
#define P_TO_VIMAGE(p) NULL
#define P_TO_VNET(p) NULL
#define TD_TO_VPROCG(td) &vprocg_0
#define P_TO_VPROCG(p) &vprocg_0
#endif /* VIMAGE */
/* Non-VIMAGE null-macros */

View File

@ -1,6 +1,8 @@
# $FreeBSD$
PROG= vimage
LDADD= -ljail
DPADD= ${LIBJAIL}
WARNS?= 2
CFLAGS+= -I../../../sys

View File

@ -27,122 +27,120 @@
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/vimage.h>
#include <net/if.h>
#include <errno.h>
#include <jail.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void
vi_print(struct vi_req *vi_req)
{
#define VI_CREATE 0x00000001
#define VI_DESTROY 0x00000002
#define VI_SWITCHTO 0x00000008
#define VI_IFACE 0x00000010
#define VI_GET 0x00000100
#define VI_GETNEXT 0x00000200
printf("\"%s\":\n", vi_req->vi_name);
printf(" %d sockets, %d ifnets, %d processes\n",
vi_req->vi_sock_count, vi_req->vi_if_count, vi_req->vi_proc_count);
}
static int getjail(char *name, int lastjid, int *vnet);
int
main(int argc, char **argv)
{
int s;
char *shell;
int cmd = VI_SWITCHTO;
struct vi_req vi_req;
int cmd;
int jid, vnet;
struct ifreq ifreq;
char name[MAXHOSTNAMELEN];
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
goto abort;
switch (argc) {
bzero(&vi_req, sizeof(vi_req));
strcpy(vi_req.vi_name, "."); /* . = this vimage. */
case 1:
cmd = 0;
break;
if (argc == 1)
cmd = VI_GET;
case 2:
if (strcmp(argv[1], "-l") == 0)
cmd = VI_GETNEXT;
else if (strcmp(argv[1], "-lr") == 0)
cmd = VI_GETNEXT;
else {
strcpy(name, argv[1]);
cmd = VI_SWITCHTO;
}
break;
if (argc == 2 && strcmp(argv[1], "-l") == 0)
cmd = VI_GETNEXT;
if (argc == 2 && strcmp(argv[1], "-lr") == 0)
cmd = VI_GETNEXT_RECURSE;
if (argc == 3) {
strcpy(vi_req.vi_name, argv[2]);
case 3:
strcpy(name, argv[2]);
if (strcmp(argv[1], "-l") == 0)
cmd = VI_GET;
if (strcmp(argv[1], "-c") == 0)
cmd = VI_CREATE;
if (strcmp(argv[1], "-d") == 0)
cmd = VI_DESTROY;
}
break;
if (argc >= 3) {
strcpy(vi_req.vi_name, argv[2]);
default:
strcpy(name, argv[2]);
if (strcmp(argv[1], "-c") == 0)
cmd = VI_CREATE;
if (strcmp(argv[1], "-i") == 0)
cmd = VI_IFACE;
}
vi_req.vi_api_cookie = VI_API_COOKIE;
vi_req.vi_req_action = cmd;
switch (cmd) {
case VI_GET:
if (ioctl(s, SIOCGPVIMAGE, (caddr_t)&vi_req) < 0)
jid = getjail(name, -1, &vnet);
if (jid < 0)
goto abort;
if (argc == 1)
printf("%s\n", vi_req.vi_name);
else
vi_print(&vi_req);
printf("%d: %s%s\n", jid, name, vnet ? "" : " (no vnet)");
exit(0);
case VI_GETNEXT:
case VI_GETNEXT_RECURSE:
vi_req.vi_req_action = VI_GET;
if (ioctl(s, SIOCGPVIMAGE, (caddr_t)&vi_req) < 0)
goto abort;
vi_print(&vi_req);
vi_req.vi_req_action = VI_GETNEXT_RECURSE;
while (ioctl(s, SIOCGPVIMAGE, (caddr_t)&vi_req) == 0) {
vi_print(&vi_req);
vi_req.vi_req_action = cmd;
}
jid = 0;
while ((jid = getjail(name, jid, &vnet)) > 0)
printf("%d: %s%s\n", jid, name,
vnet ? "" : " (no vnet)");
exit(0);
case VI_IFACE:
strncpy(vi_req.vi_if_xname, argv[3],
sizeof(vi_req.vi_if_xname));
if (ioctl(s, SIOCSIFVIMAGE, (caddr_t)&vi_req) < 0)
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
goto abort;
printf("%s@%s\n", vi_req.vi_if_xname, vi_req.vi_name);
jid = jail_getid(name);
if (jid < 0)
goto abort;
ifreq.ifr_jid = jid;
strncpy(ifreq.ifr_name, argv[3], sizeof(ifreq.ifr_name));
if (ioctl(s, SIOCSIFVNET, (caddr_t)&ifreq) < 0)
goto abort;
printf("%s@%s\n", ifreq.ifr_name, name);
exit(0);
case VI_CREATE:
if (ioctl(s, SIOCSPVIMAGE, (caddr_t)&vi_req) < 0)
if (jail_setv(JAIL_CREATE, "name", name, "vnet", NULL,
"host", NULL, "persist", NULL, NULL) < 0)
goto abort;
exit(0);
case VI_SWITCHTO:
strcpy(vi_req.vi_name, argv[1]);
if (ioctl(s, SIOCSPVIMAGE, (caddr_t)&vi_req) < 0)
jid = jail_getid(name);
if (jid < 0)
goto abort;
vi_req.vi_req_action = VI_GET;
strcpy(vi_req.vi_name, ".");
if (ioctl(s, SIOCGPVIMAGE, (caddr_t)&vi_req) < 0) {
printf("XXX this should have not happened!\n");
if (jail_attach(jid) < 0)
goto abort;
}
close(s);
if (argc == 2) {
printf("Switched to vimage %s\n", argv[1]);
printf("Switched to jail %s\n", argv[1]);
if ((shell = getenv("SHELL")) == NULL)
execlp("/bin/sh", argv[0], NULL);
else
@ -152,7 +150,10 @@ main(int argc, char **argv)
break;
case VI_DESTROY:
if (ioctl(s, SIOCSPVIMAGE, (caddr_t)&vi_req) < 0)
jid = jail_getid(name);
if (jid < 0)
goto abort;
if (jail_remove(jid) < 0)
goto abort;
exit(0);
@ -163,6 +164,35 @@ main(int argc, char **argv)
}
abort:
perror("Error");
if (jail_errmsg[0])
fprintf(stderr, "Error: %s\n", jail_errmsg);
else
perror("Error");
exit(1);
}
static int
getjail(char *name, int lastjid, int *vnet)
{
struct jailparam params[3];
int jid;
if (lastjid < 0) {
jid = jail_getid(name);
if (jid < 0)
return (jid);
jailparam_init(&params[0], "jid");
jailparam_import_raw(&params[0], &jid, sizeof jid);
} else {
jailparam_init(&params[0], "lastjid");
jailparam_import_raw(&params[0], &lastjid, sizeof lastjid);
}
jailparam_init(&params[1], "name");
jailparam_import_raw(&params[1], name, MAXHOSTNAMELEN);
name[0] = 0;
jailparam_init(&params[2], "vnet");
jailparam_import_raw(&params[2], vnet, sizeof(*vnet));
jid = jailparam_get(params, 3, 0);
jailparam_free(params, 3);
return (jid);
}