# This patch is from http://imunes.net/imunes-8.0-RC3.diff # # This patch enables per-node directories, persistent hub/switch nodes, traffic # snooping for wireshark, and disallows vlan interfaces within a jail. diff -drup src-org/sys/kern/vfs_lookup.c src/sys/kern/vfs_lookup.c --- src-org/sys/kern/vfs_lookup.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/kern/vfs_lookup.c 2009-11-11 12:46:02.000000000 +0000 @@ -59,6 +59,8 @@ __FBSDID("$FreeBSD: src/sys/kern/vfs_loo #include #endif +#include + #include #include @@ -72,6 +74,19 @@ SDT_PROBE_DEFINE3(vfs, namei, lookup, en "unsigned long"); SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *"); +#ifdef VIMAGE +#define IMUNES_SYMLINK_HACK +#endif + +#ifdef IMUNES_SYMLINK_HACK +static VNET_DEFINE(int, morphing_symlinks); +#define V_morphing_symlinks VNET(morphing_symlinks) + +SYSCTL_VNET_INT(_vfs, OID_AUTO, morphing_symlinks, CTLFLAG_RW, + &VNET_NAME(morphing_symlinks), 0, + "Resolve @ to vimage name in symlinks"); +#endif + /* * Allocation zone for namei */ @@ -333,6 +348,44 @@ namei(struct nameidata *ndp) error = ENOENT; break; } +#ifdef IMUNES_SYMLINK_HACK + /* + * If the symbolic link includes a special character '@', + * and V_morphing_symlinks is set, substitute the first + * occurence of '@' with full path to jail / vimage name. + * If the full path includes subhierarchies, s/./\// when + * expanding '@' to jail / vimage name. + * + * XXX revisit buffer length checking. + */ + CURVNET_SET_QUIET(TD_TO_VNET(curthread)); + if (V_morphing_symlinks) { + char *sp = strchr(cp, '@'); + + if (sp) { + char *vname = td->td_ucred->cr_prison->pr_name; + int vnamelen = strlen(vname); + int i; + + if (vnamelen >= auio.uio_resid) { + if (ndp->ni_pathlen > 1) + uma_zfree(namei_zone, cp); + error = ENAMETOOLONG; + CURVNET_RESTORE(); + break; + } + bcopy(sp + 1, sp + vnamelen, + linklen - (sp - cp)); + bcopy(td->td_ucred->cr_prison->pr_name, + sp, vnamelen); + linklen += (vnamelen - 1); + for (i = 0; i < vnamelen; i++) + if (sp[i] == '.') + sp[i] = '/'; + } + } + CURVNET_RESTORE(); +#endif if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); diff -drup src-org/sys/net/bpf.c src/sys/net/bpf.c --- src-org/sys/net/bpf.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/bpf.c 2009-11-11 12:46:02.000000000 +0000 @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: src/sys/net/bpf.c,v #include #include #include +#include #include #include #include @@ -1435,9 +1436,34 @@ bpf_setif(struct bpf_d *d, struct ifreq struct bpf_if *bp; struct ifnet *theywant; +#define XVNET_BPF_SNOOPING +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + struct vnet *target_vnet = curvnet; + char *c; + + /* Attempt to attach to an ifnet in a foreign vnet, specified as @ */ + c = rindex(ifr->ifr_name, '@'); + if ( c != NULL ) { + struct prison *target_pr; + + *c++ = 0; + if (!isascii(*c) && !isdigit(*c)) + return ENXIO; + target_pr = prison_find_name(curthread->td_ucred->cr_prison, c); + if (target_pr == NULL) + return ENXIO; + target_vnet = target_pr->pr_vnet; + } + CURVNET_SET_QUIET(target_vnet); +#endif + theywant = ifunit(ifr->ifr_name); - if (theywant == NULL || theywant->if_bpf == NULL) + if (theywant == NULL || theywant->if_bpf == NULL) { +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + CURVNET_RESTORE(); +#endif return (ENXIO); + } bp = theywant->if_bpf; @@ -1477,6 +1503,9 @@ bpf_setif(struct bpf_d *d, struct ifreq BPFD_LOCK(d); reset_d(d); BPFD_UNLOCK(d); +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + CURVNET_RESTORE(); +#endif return (0); } diff -drup src-org/sys/net/if.c src/sys/net/if.c --- src-org/sys/net/if.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if.c 2009-11-11 12:46:02.000000000 +0000 @@ -813,6 +813,14 @@ if_detach_internal(struct ifnet *ifp, in struct ifnet *iter; int found = 0; + /* + * Detach from any vlan, bridge or lagg ifnets linked to us. + * A small though unlikely window for a race from here to ifp + * unlinking from ifnet list is possible, hence we repeat the + * procedure once again further bellow. XXX. + */ + EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); + IFNET_WLOCK(); TAILQ_FOREACH(iter, &V_ifnet, if_link) if (iter == ifp) { diff -drup src-org/sys/net/if_llatbl.c src/sys/net/if_llatbl.c --- src-org/sys/net/if_llatbl.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if_llatbl.c 2009-11-11 12:53:49.000000000 +0000 @@ -57,11 +57,14 @@ __FBSDID("$FreeBSD: src/sys/net/if_llatb MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); -static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables); +static VNET_DEFINE(SLIST_HEAD(, lltable), lltables); +#define V_lltables VNET(lltables) extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, u_char *); +static void vnet_lltable_init(void); + struct rwlock lltable_rwlock; RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); @@ -75,7 +78,7 @@ lltable_sysctl_dumparp(int af, struct sy int error = 0; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af == af) { error = llt->llt_dump(llt, wr); if (error != 0) @@ -157,7 +160,7 @@ lltable_free(struct lltable *llt) KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); LLTABLE_WLOCK(); - SLIST_REMOVE(&lltables, llt, lltable, llt_link); + SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); LLTABLE_WUNLOCK(); for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { @@ -180,7 +183,7 @@ lltable_drain(int af) register int i; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af != af) continue; @@ -202,7 +205,7 @@ lltable_prefix_free(int af, struct socka struct lltable *llt; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af != af) continue; @@ -232,7 +235,7 @@ lltable_init(struct ifnet *ifp, int af) LIST_INIT(&llt->lle_head[i]); LLTABLE_WLOCK(); - SLIST_INSERT_HEAD(&lltables, llt, llt_link); + SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); LLTABLE_WUNLOCK(); return (llt); @@ -302,7 +305,7 @@ lla_rt_output(struct rt_msghdr *rtm, str /* XXX linked list may be too expensive */ LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af == dst->sa_family && llt->llt_ifp == ifp) break; @@ -367,3 +370,12 @@ lla_rt_output(struct rt_msghdr *rtm, str return (error); } + +static void +vnet_lltable_init() +{ + + SLIST_INIT(&V_lltables); +} +VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, vnet_lltable_init, NULL); + diff -drup src-org/sys/net/if_vlan.c src/sys/net/if_vlan.c --- src-org/sys/net/if_vlan.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if_vlan.c 2009-11-11 12:46:02.000000000 +0000 @@ -1359,6 +1359,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); if (error) break; +#ifdef VIMAGE + if (ifp->if_home_vnet != ifp->if_vnet) { + error = EPERM; + break; + } +#endif if (vlr.vlr_parent[0] == '\0') { vlan_unconfig(ifp); break; @@ -1386,6 +1392,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd case SIOCGETVLAN: bzero(&vlr, sizeof(vlr)); +#ifdef VIMAGE + if (ifp->if_home_vnet != ifp->if_vnet) { + error = EPERM; + break; + } +#endif VLAN_LOCK(); if (TRUNK(ifv) != NULL) { strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, diff -drup src-org/sys/netgraph/ng_bridge.c src/sys/netgraph/ng_bridge.c --- src-org/sys/netgraph/ng_bridge.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/netgraph/ng_bridge.c 2009-11-11 12:46:02.000000000 +0000 @@ -105,6 +105,7 @@ struct ng_bridge_private { u_int numBuckets; /* num buckets in table */ u_int hashMask; /* numBuckets - 1 */ int numLinks; /* num connected links */ + int persistent; /* can exist w/o any hooks */ struct callout timer; /* one second periodic timer */ }; typedef struct ng_bridge_private *priv_p; @@ -345,13 +346,13 @@ static int ng_bridge_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); + int linkNum = -1; /* Check for a link hook */ if (strncmp(name, NG_BRIDGE_HOOK_LINK_PREFIX, strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) == 0) { const char *cp; char *eptr; - u_long linkNum; cp = name + strlen(NG_BRIDGE_HOOK_LINK_PREFIX); if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) @@ -359,6 +360,12 @@ ng_bridge_newhook(node_p node, hook_p ho linkNum = strtoul(cp, &eptr, 10); if (*eptr != '\0' || linkNum >= NG_BRIDGE_MAX_LINKS) return (EINVAL); + } else if (strcmp(name, "anchor") == 0) { + linkNum = 0; + priv->persistent = 1; + } + + if (linkNum >= 0 ) { if (priv->links[linkNum] != NULL) return (EISCONN); priv->links[linkNum] = malloc(sizeof(*priv->links[linkNum]), @@ -366,7 +373,7 @@ ng_bridge_newhook(node_p node, hook_p ho if (priv->links[linkNum] == NULL) return (ENOMEM); priv->links[linkNum]->hook = hook; - NG_HOOK_SET_PRIVATE(hook, (void *)linkNum); + NG_HOOK_SET_PRIVATE(hook, (void *)(intptr_t)linkNum); priv->numLinks++; return (0); } @@ -799,7 +806,8 @@ ng_bridge_disconnect(hook_p hook) /* If no more hooks, go away */ if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) - && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) { + && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) + && !priv->persistent) { ng_rmnode_self(NG_HOOK_NODE(hook)); } return (0); diff -drup src-org/sys/netgraph/ng_hub.c src/sys/netgraph/ng_hub.c --- src-org/sys/netgraph/ng_hub.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/netgraph/ng_hub.c 2009-11-11 12:46:02.000000000 +0000 @@ -37,6 +37,7 @@ #include static ng_constructor_t ng_hub_constructor; +static ng_newhook_t ng_hub_newhook; static ng_rcvdata_t ng_hub_rcvdata; static ng_disconnect_t ng_hub_disconnect; @@ -44,6 +45,7 @@ static struct ng_type ng_hub_typestruct .version = NG_ABI_VERSION, .name = NG_HUB_NODE_TYPE, .constructor = ng_hub_constructor, + .newhook = ng_hub_newhook, .rcvdata = ng_hub_rcvdata, .disconnect = ng_hub_disconnect, }; @@ -57,6 +59,14 @@ ng_hub_constructor(node_p node) return (0); } +static int +ng_hub_newhook(node_p node, hook_p hook, const char *name) +{ + if (strcmp(name, "anchor") == 0) + node->nd_private = (void *) 1; + return (0); +} + static int ng_hub_rcvdata(hook_p hook, item_p item) { @@ -94,7 +104,7 @@ ng_hub_disconnect(hook_p hook) { if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && - NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) + NG_NODE_IS_VALID(NG_HOOK_NODE(hook)) && !hook->hk_node->nd_private) ng_rmnode_self(NG_HOOK_NODE(hook)); return (0); }