summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tap.c
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-02-04 16:32:46 +0000
committerbms <bms@FreeBSD.org>2007-02-04 16:32:46 +0000
commit77c2e113090f513f7876ee5e02f61ab600b319cf (patch)
tree2b8098cffbe0971d05ca5c30201a51b937a1e7f9 /sys/net/if_tap.c
parent4e9c971afca066f77117383709ba6fa8ee6a6f12 (diff)
downloadFreeBSD-src-77c2e113090f513f7876ee5e02f61ab600b319cf.zip
FreeBSD-src-77c2e113090f513f7876ee5e02f61ab600b319cf.tar.gz
Implement ifnet cloning for tun(4)/tap(4).
Make devfs cloning a sysctl/tunable which defaults to on. If devfs cloning is enabled, only the super-user may create tun(4)/tap(4)/vmnet(4) instances. Devfs cloning is still enabled by default; it may be disabled from the loader or via sysctl with "net.link.tap.devfs_cloning" and "net.link.tun.devfs_cloning". Disabling its use affects potentially all tun(4)/tap(4) consumers including OpenSSH, OpenVPN and VMware. PR: 105228 (potentially also 90413, 105570) Submitted by: Landon Fuller Tested by: Andrej Tobola Approved by: core (rwatson) MFC after: 4 weeks
Diffstat (limited to 'sys/net/if_tap.c')
-rw-r--r--sys/net/if_tap.c158
1 files changed, 126 insertions, 32 deletions
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 653d618..9fa10b5 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -62,6 +62,7 @@
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <net/if_types.h>
@@ -93,6 +94,14 @@ static void tapifstart(struct ifnet *);
static int tapifioctl(struct ifnet *, u_long, caddr_t);
static void tapifinit(void *);
+static int tap_clone_create(struct if_clone *, int, caddr_t);
+static void tap_clone_destroy(struct ifnet *);
+static int vmnet_clone_create(struct if_clone *, int, caddr_t);
+static void vmnet_clone_destroy(struct ifnet *);
+
+IFC_SIMPLE_DECLARE(tap, 0);
+IFC_SIMPLE_DECLARE(vmnet, 0);
+
/* character device */
static d_open_t tapopen;
static d_close_t tapclose;
@@ -142,6 +151,7 @@ static struct cdevsw tap_cdevsw = {
static struct mtx tapmtx;
static int tapdebug = 0; /* debug flag */
static int tapuopen = 0; /* allow user open() */
+static int tapdclone = 1; /* enable devfs cloning */
static SLIST_HEAD(, tap_softc) taphead; /* first device */
static struct clonedevs *tapclones;
@@ -154,10 +164,87 @@ SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
"Ethernet tunnel software network interface");
SYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
"Allow user to open /dev/tap (based on node permissions)");
+SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0,
+ "Enably legacy devfs interface creation");
SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
+TUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone);
+
DEV_MODULE(if_tap, tapmodevent, NULL);
+static int
+tap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+{
+ struct cdev *dev;
+ int i;
+ int extra;
+
+ if (strcmp(ifc->ifc_name, VMNET) == 0)
+ extra = VMNET_DEV_MASK;
+ else
+ extra = 0;
+
+ /* find any existing device, or allocate new unit number */
+ i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra);
+ if (i) {
+ dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
+ UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit);
+ if (dev != NULL) {
+ dev_ref(dev);
+ dev->si_flags |= SI_CHEAPCLONE;
+ }
+ }
+
+ tapcreate(dev);
+ return (0);
+}
+
+/* vmnet devices are tap devices in disguise */
+static int
+vmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+{
+ return tap_clone_create(ifc, unit, params);
+}
+
+static void
+tap_destroy(struct tap_softc *tp)
+{
+ struct ifnet *ifp = tp->tap_ifp;
+ int s;
+
+ /* Unlocked read. */
+ KASSERT(!(tp->tap_flags & TAP_OPEN),
+ ("%s flags is out of sync", ifp->if_xname));
+
+ knlist_destroy(&tp->tap_rsel.si_note);
+ destroy_dev(tp->tap_dev);
+ s = splimp();
+ ether_ifdetach(ifp);
+ if_free_type(ifp, IFT_ETHER);
+ splx(s);
+
+ mtx_destroy(&tp->tap_mtx);
+ free(tp, M_TAP);
+}
+
+static void
+tap_clone_destroy(struct ifnet *ifp)
+{
+ struct tap_softc *tp = ifp->if_softc;
+
+ mtx_lock(&tapmtx);
+ SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
+ mtx_unlock(&tapmtx);
+ tap_destroy(tp);
+}
+
+/* vmnet devices are tap devices in disguise */
+static void
+vmnet_clone_destroy(struct ifnet *ifp)
+{
+ tap_clone_destroy(ifp);
+}
+
/*
* tapmodevent
*
@@ -169,7 +256,6 @@ tapmodevent(module_t mod, int type, void *data)
static eventhandler_tag eh_tag = NULL;
struct tap_softc *tp = NULL;
struct ifnet *ifp = NULL;
- int s;
switch (type) {
case MOD_LOAD:
@@ -186,6 +272,8 @@ tapmodevent(module_t mod, int type, void *data)
mtx_destroy(&tapmtx);
return (ENOMEM);
}
+ if_clone_attach(&tap_cloner);
+ if_clone_attach(&vmnet_cloner);
return (0);
case MOD_UNLOAD:
@@ -207,6 +295,8 @@ tapmodevent(module_t mod, int type, void *data)
mtx_unlock(&tapmtx);
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
+ if_clone_detach(&tap_cloner);
+ if_clone_detach(&vmnet_cloner);
mtx_lock(&tapmtx);
while ((tp = SLIST_FIRST(&taphead)) != NULL) {
@@ -217,19 +307,7 @@ tapmodevent(module_t mod, int type, void *data)
TAPDEBUG("detaching %s\n", ifp->if_xname);
- /* Unlocked read. */
- KASSERT(!(tp->tap_flags & TAP_OPEN),
- ("%s flags is out of sync", ifp->if_xname));
-
- knlist_destroy(&tp->tap_rsel.si_note);
- destroy_dev(tp->tap_dev);
- s = splimp();
- ether_ifdetach(ifp);
- if_free_type(ifp, IFT_ETHER);
- splx(s);
-
- mtx_destroy(&tp->tap_mtx);
- free(tp, M_TAP);
+ tap_destroy(tp);
mtx_lock(&tapmtx);
}
mtx_unlock(&tapmtx);
@@ -255,38 +333,63 @@ tapmodevent(module_t mod, int type, void *data)
static void
tapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
{
+ char devname[SPECNAMELEN + 1];
+ int i, unit, append_unit;
int extra;
- int i, unit;
- char *device_name = name;
if (*dev != NULL)
return;
- device_name = TAP;
+ /*
+ * If tap cloning is enabled, only the superuser can create
+ * an interface.
+ */
+ if (!tapdclone || priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)
+ return;
+
+ unit = 0;
+ append_unit = 0;
extra = 0;
+
+ /* We're interested in only tap/vmnet devices. */
if (strcmp(name, TAP) == 0) {
unit = -1;
} else if (strcmp(name, VMNET) == 0) {
- device_name = VMNET;
- extra = VMNET_DEV_MASK;
unit = -1;
- } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
- device_name = VMNET;
extra = VMNET_DEV_MASK;
- if (dev_stdclone(name, NULL, device_name, &unit) != 1)
+ } else if (dev_stdclone(name, NULL, TAP, &unit) != 1) {
+ if (dev_stdclone(name, NULL, VMNET, &unit) != 1) {
return;
+ } else {
+ extra = VMNET_DEV_MASK;
+ }
}
+ if (unit == -1)
+ append_unit = 1;
+
/* find any existing device, or allocate new unit number */
i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
if (i) {
+ if (append_unit) {
+ /*
+ * We were passed 'tun' or 'tap', with no unit specified
+ * so we'll need to append it now.
+ */
+ namelen = snprintf(devname, sizeof(devname), "%s%d", name,
+ unit);
+ name = devname;
+ }
+
*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
- UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
+ UID_ROOT, GID_WHEEL, 0600, "%s", name);
if (*dev != NULL) {
dev_ref(*dev);
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
+
+ if_clone_create(name, namelen, NULL);
} /* tapclone */
@@ -385,16 +488,7 @@ tapopen(struct cdev *dev, int flag, int mode, struct thread *td)
if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
return (ENXIO);
- /*
- * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected
- * by Giant, but the race actually exists under memory pressure as
- * well even when running with Giant, as malloc() may sleep.
- */
tp = dev->si_drv1;
- if (tp == NULL) {
- tapcreate(dev);
- tp = dev->si_drv1;
- }
mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_OPEN) {
OpenPOWER on IntegriCloud