Re: vmd: fixed lladdr for VM guests to prevent MAC spoofing

2017-03-01 Thread Mike Larkin
On Wed, Mar 01, 2017 at 07:17:10PM +0100, Reyk Floeter wrote:
> On Wed, Mar 01, 2017 at 01:04:57PM +0100, Reyk Floeter wrote:
> > Hi,
> > 
> > add the new "fixed lladdr" option: when multiple VMs are connected to
> > a switch, it is desirable that an individual VM cannot spoof another
> > MAC address, especially when using meta-data*.  vmd(8) can enforce
> > this by comparing the address in the Ethernet header with the
> > configured/generated address of the VM interface.
> > 
> > This somewhat resembles the following features from VMware:
> > ethernet0.noforgedsrcaddr = "TRUE"
> > ethernet0.nopromisc = "TRUE"
> > 
> > The important parts of the diff** are in the two if statements including
> > "dev->fixedmac" below, the rest is infrastructure, config, and
> > documentation.
> > 
> > I could have used bridge(4) rules or switch(4) OpenFlow actions, but I
> > decided to implement it in vmd(8) directly to make it easier and to
> > work in all cases independent from the switch type.
> > 
> > *) https://github.com/reyk/meta-data
> > **) this diff conflicts with the previous vmm.c split.  Whatever goes
> > in first, I can update and resend it accordingly.
> > 
> > OK?
> > 
> > Reyk
> > 
> > Add "fixed lladdr" option to prevent VMs from spoofing MAC addresses.
> > 
> > This is especially useful when multiple VMs share a switch, the
> > implementation is independent from the underlying switch or bridge.
> > 
> 
> After some discussions, this is the updated diff:
> 
> - change "fixed" to "locked", adjust manpage
> - sync with latest vmm.c split
> 
> Reyk
>

no objections
 
> Index: usr.sbin/vmd/config.c
> ===
> RCS file: /cvs/src/usr.sbin/vmd/config.c,v
> retrieving revision 1.25
> diff -u -p -u -p -r1.25 config.c
> --- usr.sbin/vmd/config.c 1 Mar 2017 07:43:33 -   1.25
> +++ usr.sbin/vmd/config.c 1 Mar 2017 18:16:20 -
> @@ -236,7 +236,8 @@ config_setvm(struct privsep *ps, struct 
>   }
>  
>   /* Set the interface status */
> - vif->vif_flags = vmc->vmc_ifflags[i] & IFF_UP;
> + vif->vif_flags =
> + vmc->vmc_ifflags[i] & (VMIFF_UP|VMIFF_OPTMASK);
>   }
>  
>   /* Open TTY */
> Index: usr.sbin/vmd/parse.y
> ===
> RCS file: /cvs/src/usr.sbin/vmd/parse.y,v
> retrieving revision 1.21
> diff -u -p -u -p -r1.21 parse.y
> --- usr.sbin/vmd/parse.y  1 Mar 2017 07:43:33 -   1.21
> +++ usr.sbin/vmd/parse.y  1 Mar 2017 18:16:20 -
> @@ -116,10 +116,11 @@ typedef struct {
>  
>  %token   INCLUDE ERROR
>  %token   ADD DISK DOWN GROUP INTERFACE NIFS PATH SIZE SWITCH UP VMID
> -%token   ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER
> +%token   ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER LOCKED
>  %token STRING
>  %token NUMBER
>  %type  disable
> +%type  locked
>  %type  updown
>  %type  lladdr
>  %type  string
> @@ -174,7 +175,7 @@ switch: SWITCH string {
>  
>   vsw->sw_id = env->vmd_nswitches + 1;
>   vsw->sw_name = $2;
> - vsw->sw_flags = IFF_UP;
> + vsw->sw_flags = VMIFF_UP;
>   snprintf(vsw->sw_ifname, sizeof(vsw->sw_ifname),
>   "%s%u", vsw_type, vsw_unit++);
>   TAILQ_INIT(&vsw->sw_ifs);
> @@ -241,11 +242,14 @@ switch_opts : disable   {
>   }
>   free($2);
>   }
> + | LOCKED LLADDR {
> + vsw->sw_flags |= VMIFF_LOCKED;
> + }
>   | updown{
>   if ($1)
> - vsw->sw_flags |= IFF_UP;
> + vsw->sw_flags |= VMIFF_UP;
>   else
> - vsw->sw_flags &= ~IFF_UP;
> + vsw->sw_flags &= ~VMIFF_UP;
>   }
>   ;
>  
> @@ -503,14 +507,16 @@ iface_opts  : SWITCH string {
>   sizeof(vmc.vmc_ifgroup[i]));
>   free($2);
>   }
> - | LLADDR lladdr {
> - memcpy(vcp->vcp_macs[vcp_nnics], $2, ETHER_ADDR_LEN);
> + | locked LLADDR lladdr  {
> + if ($1)
> + vmc.vmc_ifflags[vcp_nnics] |= VMIFF_LOCKED;
> + memcpy(vcp->vcp_macs[vcp_nnics], $3, ETHER_ADDR_LEN);
>   }
>   | updown{
>   if ($1)
> - vmc.vmc_ifflags[vcp_nnics] |= IFF_UP;
> + vmc.vmc_ifflags[vcp_nnics] |= VMIFF_U

Re: vmd: fixed lladdr for VM guests to prevent MAC spoofing

2017-03-01 Thread Reyk Floeter
On Wed, Mar 01, 2017 at 01:04:57PM +0100, Reyk Floeter wrote:
> Hi,
> 
> add the new "fixed lladdr" option: when multiple VMs are connected to
> a switch, it is desirable that an individual VM cannot spoof another
> MAC address, especially when using meta-data*.  vmd(8) can enforce
> this by comparing the address in the Ethernet header with the
> configured/generated address of the VM interface.
> 
> This somewhat resembles the following features from VMware:
>   ethernet0.noforgedsrcaddr = "TRUE"
>   ethernet0.nopromisc = "TRUE"
> 
> The important parts of the diff** are in the two if statements including
> "dev->fixedmac" below, the rest is infrastructure, config, and
> documentation.
> 
> I could have used bridge(4) rules or switch(4) OpenFlow actions, but I
> decided to implement it in vmd(8) directly to make it easier and to
> work in all cases independent from the switch type.
> 
> *) https://github.com/reyk/meta-data
> **) this diff conflicts with the previous vmm.c split.  Whatever goes
> in first, I can update and resend it accordingly.
> 
> OK?
> 
> Reyk
> 
> Add "fixed lladdr" option to prevent VMs from spoofing MAC addresses.
> 
> This is especially useful when multiple VMs share a switch, the
> implementation is independent from the underlying switch or bridge.
> 

After some discussions, this is the updated diff:

- change "fixed" to "locked", adjust manpage
- sync with latest vmm.c split

Reyk

Index: usr.sbin/vmd/config.c
===
RCS file: /cvs/src/usr.sbin/vmd/config.c,v
retrieving revision 1.25
diff -u -p -u -p -r1.25 config.c
--- usr.sbin/vmd/config.c   1 Mar 2017 07:43:33 -   1.25
+++ usr.sbin/vmd/config.c   1 Mar 2017 18:16:20 -
@@ -236,7 +236,8 @@ config_setvm(struct privsep *ps, struct 
}
 
/* Set the interface status */
-   vif->vif_flags = vmc->vmc_ifflags[i] & IFF_UP;
+   vif->vif_flags =
+   vmc->vmc_ifflags[i] & (VMIFF_UP|VMIFF_OPTMASK);
}
 
/* Open TTY */
Index: usr.sbin/vmd/parse.y
===
RCS file: /cvs/src/usr.sbin/vmd/parse.y,v
retrieving revision 1.21
diff -u -p -u -p -r1.21 parse.y
--- usr.sbin/vmd/parse.y1 Mar 2017 07:43:33 -   1.21
+++ usr.sbin/vmd/parse.y1 Mar 2017 18:16:20 -
@@ -116,10 +116,11 @@ typedef struct {
 
 %token INCLUDE ERROR
 %token ADD DISK DOWN GROUP INTERFACE NIFS PATH SIZE SWITCH UP VMID
-%token ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER
+%token ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER LOCKED
 %token   STRING
 %token   NUMBER
 %typedisable
+%typelocked
 %typeupdown
 %typelladdr
 %typestring
@@ -174,7 +175,7 @@ switch  : SWITCH string {
 
vsw->sw_id = env->vmd_nswitches + 1;
vsw->sw_name = $2;
-   vsw->sw_flags = IFF_UP;
+   vsw->sw_flags = VMIFF_UP;
snprintf(vsw->sw_ifname, sizeof(vsw->sw_ifname),
"%s%u", vsw_type, vsw_unit++);
TAILQ_INIT(&vsw->sw_ifs);
@@ -241,11 +242,14 @@ switch_opts   : disable   {
}
free($2);
}
+   | LOCKED LLADDR {
+   vsw->sw_flags |= VMIFF_LOCKED;
+   }
| updown{
if ($1)
-   vsw->sw_flags |= IFF_UP;
+   vsw->sw_flags |= VMIFF_UP;
else
-   vsw->sw_flags &= ~IFF_UP;
+   vsw->sw_flags &= ~VMIFF_UP;
}
;
 
@@ -503,14 +507,16 @@ iface_opts: SWITCH string {
sizeof(vmc.vmc_ifgroup[i]));
free($2);
}
-   | LLADDR lladdr {
-   memcpy(vcp->vcp_macs[vcp_nnics], $2, ETHER_ADDR_LEN);
+   | locked LLADDR lladdr  {
+   if ($1)
+   vmc.vmc_ifflags[vcp_nnics] |= VMIFF_LOCKED;
+   memcpy(vcp->vcp_macs[vcp_nnics], $3, ETHER_ADDR_LEN);
}
| updown{
if ($1)
-   vmc.vmc_ifflags[vcp_nnics] |= IFF_UP;
+   vmc.vmc_ifflags[vcp_nnics] |= VMIFF_UP;
else
-   vmc.vmc_ifflags[vcp_nnics] &= ~IFF_UP;
+   vmc.vmc_ifflags[vcp_nnics] &= ~VMIFF_UP;
}
;
 
@@ -541,6 +547,10 @@ lladdr : STRING  

vmd: fixed lladdr for VM guests to prevent MAC spoofing

2017-03-01 Thread Reyk Floeter
Hi,

add the new "fixed lladdr" option: when multiple VMs are connected to
a switch, it is desirable that an individual VM cannot spoof another
MAC address, especially when using meta-data*.  vmd(8) can enforce
this by comparing the address in the Ethernet header with the
configured/generated address of the VM interface.

This somewhat resembles the following features from VMware:
ethernet0.noforgedsrcaddr = "TRUE"
ethernet0.nopromisc = "TRUE"

The important parts of the diff** are in the two if statements including
"dev->fixedmac" below, the rest is infrastructure, config, and
documentation.

I could have used bridge(4) rules or switch(4) OpenFlow actions, but I
decided to implement it in vmd(8) directly to make it easier and to
work in all cases independent from the switch type.

*) https://github.com/reyk/meta-data
**) this diff conflicts with the previous vmm.c split.  Whatever goes
in first, I can update and resend it accordingly.

OK?

Reyk

Add "fixed lladdr" option to prevent VMs from spoofing MAC addresses.

This is especially useful when multiple VMs share a switch, the
implementation is independent from the underlying switch or bridge.

diff --git usr.sbin/vmd/config.c usr.sbin/vmd/config.c
index fa5dda1..7863ce1 100644
--- usr.sbin/vmd/config.c
+++ usr.sbin/vmd/config.c
@@ -236,7 +236,8 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, 
uint32_t peerid, uid_t uid)
}
 
/* Set the interface status */
-   vif->vif_flags = vmc->vmc_ifflags[i] & IFF_UP;
+   vif->vif_flags =
+   vmc->vmc_ifflags[i] & (VMIFF_UP|VMIFF_OPTMASK);
}
 
/* Open TTY */
diff --git usr.sbin/vmd/parse.y usr.sbin/vmd/parse.y
index 52ea73e..6f35368 100644
--- usr.sbin/vmd/parse.y
+++ usr.sbin/vmd/parse.y
@@ -116,10 +116,11 @@ typedef struct {
 
 %token INCLUDE ERROR
 %token ADD DISK DOWN GROUP INTERFACE NIFS PATH SIZE SWITCH UP VMID
-%token ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER
+%token ENABLE DISABLE VM KERNEL LLADDR MEMORY OWNER FIXED
 %token   STRING
 %token   NUMBER
 %typedisable
+%typefixed
 %typeupdown
 %typelladdr
 %typestring
@@ -174,7 +175,7 @@ switch  : SWITCH string {
 
vsw->sw_id = env->vmd_nswitches + 1;
vsw->sw_name = $2;
-   vsw->sw_flags = IFF_UP;
+   vsw->sw_flags = VMIFF_UP;
snprintf(vsw->sw_ifname, sizeof(vsw->sw_ifname),
"%s%u", vsw_type, vsw_unit++);
TAILQ_INIT(&vsw->sw_ifs);
@@ -241,11 +242,14 @@ switch_opts   : disable   {
}
free($2);
}
+   | FIXED LLADDR  {
+   vsw->sw_flags |= VMIFF_FIXED;
+   }
| updown{
if ($1)
-   vsw->sw_flags |= IFF_UP;
+   vsw->sw_flags |= VMIFF_UP;
else
-   vsw->sw_flags &= ~IFF_UP;
+   vsw->sw_flags &= ~VMIFF_UP;
}
;
 
@@ -503,14 +507,16 @@ iface_opts: SWITCH string {
sizeof(vmc.vmc_ifgroup[i]));
free($2);
}
-   | LLADDR lladdr {
-   memcpy(vcp->vcp_macs[vcp_nnics], $2, ETHER_ADDR_LEN);
+   | fixed LLADDR lladdr   {
+   if ($1)
+   vmc.vmc_ifflags[vcp_nnics] |= VMIFF_FIXED;
+   memcpy(vcp->vcp_macs[vcp_nnics], $3, ETHER_ADDR_LEN);
}
| updown{
if ($1)
-   vmc.vmc_ifflags[vcp_nnics] |= IFF_UP;
+   vmc.vmc_ifflags[vcp_nnics] |= VMIFF_UP;
else
-   vmc.vmc_ifflags[vcp_nnics] &= ~IFF_UP;
+   vmc.vmc_ifflags[vcp_nnics] &= ~VMIFF_UP;
}
;
 
@@ -541,6 +547,10 @@ lladdr : STRING{
}
;
 
+fixed  : /* empty */   { $$ = 0; }
+   | FIXED { $$ = 1; }
+   ;
+
 updown : UP{ $$ = 1; }
| DOWN  { $$ = 0; }
;
@@ -599,6 +609,7 @@ lookup(char *s)
{ "disk",   DISK },
{ "down",   DOWN },
{ "enable", ENABLE },
+   { "fixed",  FIXED },
{ "group",