Update default_nic_type implementation within VirtualBox provider
In some cases the E1000 NIC type is the only acceptable value. Since defaulting causes breakages to existing boxes, leave the default value as `nil` but check the VirtualBox version in use and print warning to user if VirtualBox version is vulnerable and E1000 NIC types are configured for use within defined network adapters.
This commit is contained in:
parent
45766ad00e
commit
d589aa9f81
|
@ -42,6 +42,7 @@ module VagrantPlugins
|
|||
autoload :PrepareForwardedPortCollisionParams, File.expand_path("../action/prepare_forwarded_port_collision_params", __FILE__)
|
||||
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
||||
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
||||
autoload :SetDefaultNICType, File.expand_path("../action/set_default_nic_type", __FILE__)
|
||||
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
|
||||
autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
|
||||
autoload :SnapshotRestore, File.expand_path("../action/snapshot_restore", __FILE__)
|
||||
|
@ -71,6 +72,7 @@ module VagrantPlugins
|
|||
b.use SyncedFolderCleanup
|
||||
b.use SyncedFolders
|
||||
b.use PrepareNFSSettings
|
||||
b.use SetDefaultNICType
|
||||
b.use ClearNetworkInterfaces
|
||||
b.use Network
|
||||
b.use NetworkFixIPv6
|
||||
|
|
|
@ -37,8 +37,6 @@ module VagrantPlugins
|
|||
available_slots.delete(slot)
|
||||
end
|
||||
|
||||
default_nic_type = env[:machine].provider_config.default_nic_type
|
||||
|
||||
@logger.debug("Available slots for high-level adapters: #{available_slots.inspect}")
|
||||
@logger.info("Determining network adapters required for high-level configuration...")
|
||||
available_slots = available_slots.to_a.sort
|
||||
|
@ -46,11 +44,6 @@ module VagrantPlugins
|
|||
# We only handle private and public networks
|
||||
next if type != :private_network && type != :public_network
|
||||
|
||||
if default_nic_type && !options.key?(:nic_type) && !options.key?(:virtualbox__nic_type)
|
||||
@logger.info("Setting default nic type (`#{default_nic_type}`) for `#{type}` - `#{options}`")
|
||||
options[:virtualbox__nic_type] = default_nic_type
|
||||
end
|
||||
|
||||
options = scoped_hash_override(options, :virtualbox)
|
||||
|
||||
# Figure out the slot that this adapter will go into
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderVirtualBox
|
||||
module Action
|
||||
# This sets the default NIC type used for network adapters created
|
||||
# on the guest. Also includes a check of NIC types in use and VirtualBox
|
||||
# version to determine if E1000 NIC types are vulnerable.
|
||||
#
|
||||
# NOTE: Vulnerability was fixed here: https://www.virtualbox.org/changeset/75330/vbox
|
||||
class SetDefaultNICType
|
||||
# Defines versions of VirtualBox with susceptible implementation
|
||||
# of the E1000 devices.
|
||||
E1000_SUSCEPTIBLE = Gem::Requirement.new("<= 5.2.22").freeze
|
||||
|
||||
def initialize(app, env)
|
||||
@logger = Log4r::Logger.new("vagrant::plugins::virtualbox::set_default_nic_type")
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
default_nic_type = env[:machine].provider_config.default_nic_type
|
||||
|
||||
e1000_in_use = [
|
||||
# simple check on default_nic_type
|
||||
->{ default_nic_type.nil? || default_nic_type.to_s.start_with?("8254") },
|
||||
# check provider defined adapters
|
||||
->{ env[:machine].provider_config.network_adapters.values.detect{ |_, opts|
|
||||
opts[:nic_type].to_s.start_with?("8254") } },
|
||||
# finish with inspecting configured networks
|
||||
->{ env[:machine].config.vm.networks.detect{ |_, opts|
|
||||
opts.fetch(:virtualbox__nic_type, opts[:nic_type]).to_s.start_with?("8254") } }
|
||||
]
|
||||
|
||||
# Check if VirtualBox E1000 implementation is vulnerable
|
||||
if E1000_SUSCEPTIBLE.satisfied_by?(Gem::Version.new(env[:machine].provider.driver.version))
|
||||
@logger.info("Detected VirtualBox version with susceptible E1000 implementation (`#{E1000_SUSCEPTIBLE}`)")
|
||||
if e1000_in_use.any?(&:call)
|
||||
env[:ui].warn I18n.t("vagrant.actions.vm.set_default_nic_type.e1000_warning")
|
||||
end
|
||||
end
|
||||
|
||||
if default_nic_type
|
||||
@logger.info("Default NIC type for VirtualBox interfaces `#{default_nic_type}`")
|
||||
# Update network adapters defined in provider configuration
|
||||
env[:machine].provider_config.network_adapters.each do |slot, args|
|
||||
_, opts = args
|
||||
if opts && !opts.key?(:nic_type)
|
||||
@logger.info("Setting default NIC type (`#{default_nic_type}`) adapter `#{slot}` - `#{args}`")
|
||||
opts[:nic_type] = default_nic_type
|
||||
end
|
||||
end
|
||||
|
||||
# Update generally defined networks
|
||||
env[:machine].config.vm.networks.each do |type, options|
|
||||
next if !type.to_s.end_with?("_network")
|
||||
if !options.key?(:nic_type) && !options.key?(:virtualbox__nic_type)
|
||||
@logger.info("Setting default NIC type (`#{default_nic_type}`) for `#{type}` - `#{options}`")
|
||||
options[:virtualbox__nic_type] = default_nic_type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -20,8 +20,8 @@ module VagrantPlugins
|
|||
attr_reader :customizations
|
||||
|
||||
# Set the default type of NIC hardware to be used for network
|
||||
# devices. By default this is "virtio". If it is set to `nil`
|
||||
# no type will be set and VirtualBox's default will be used.
|
||||
# devices. By default this is `nil` and VirtualBox's default
|
||||
# will be used.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :default_nic_type
|
||||
|
@ -167,8 +167,7 @@ module VagrantPlugins
|
|||
# The default name is just nothing, and we default it
|
||||
@name = nil if @name == UNSET_VALUE
|
||||
|
||||
@default_nic_type = "virtio" if @default_nic_type == UNSET_VALUE
|
||||
set_default_nic_type! if @default_nic_type
|
||||
@default_nic_type = nil if @default_nic_type == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
|
@ -201,15 +200,6 @@ module VagrantPlugins
|
|||
{ "VirtualBox Provider" => errors }
|
||||
end
|
||||
|
||||
def set_default_nic_type!
|
||||
network_adapters.each do |_, args|
|
||||
_, opts = args
|
||||
if opts && !opts.key?(:nic_type)
|
||||
opts[:nic_type] = @default_nic_type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"VirtualBox"
|
||||
end
|
||||
|
|
|
@ -2300,6 +2300,17 @@ en:
|
|||
mounting: Mounting shared folders...
|
||||
mounting_entry: "%{guestpath} => %{hostpath}"
|
||||
nomount_entry: "Automounting disabled: %{hostpath}"
|
||||
set_default_nic_type:
|
||||
e1000_warning: |-
|
||||
Vagrant has detected a configuration issue which exposes a
|
||||
vulnerability with the installed version of VirtualBox. The
|
||||
current guest is configured to use an E1000 NIC type for a
|
||||
network adapter which is vulnerable in this version of VirtualBox.
|
||||
Ensure the guest is trusted to use this configuration or update
|
||||
the NIC type using one of the methods below:
|
||||
|
||||
https://www.vagrantup.com/docs/virtualbox/configuration.html#default-nic-type
|
||||
https://www.vagrantup.com/docs/virtualbox/networking.html#virtualbox-nic-type
|
||||
set_name:
|
||||
setting_name: |-
|
||||
Setting the name of the VM: %{name}
|
||||
|
|
|
@ -84,42 +84,6 @@ describe VagrantPlugins::ProviderVirtualBox::Action::Network do
|
|||
expect{ subject.call(env) }.not_to raise_error(Vagrant::Errors::NetworkAddressInvalid)
|
||||
end
|
||||
|
||||
describe "setting nic type" do
|
||||
before do
|
||||
guest = double("guest")
|
||||
allow(driver).to receive(:read_bridged_interfaces) { [] }
|
||||
allow(driver).to receive(:read_host_only_interfaces) { [] }
|
||||
allow(driver).to receive(:create_host_only_network) { {} }
|
||||
allow(driver).to receive(:read_dhcp_servers) { [] }
|
||||
allow(driver).to receive(:create_dhcp_server)
|
||||
allow(machine).to receive(:guest) { guest }
|
||||
allow(guest).to receive(:capability)
|
||||
end
|
||||
|
||||
it "sets default nic type when unset" do
|
||||
machine.config.vm.network 'private_network', { type: 'dhcp' }
|
||||
subject.call(env)
|
||||
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
||||
expect(net_config[:virtualbox__nic_type]).to eq("virtio")
|
||||
end
|
||||
|
||||
it "does not set nic type when already set" do
|
||||
machine.config.vm.network 'private_network', { type: 'dhcp', nic_type: "custom" }
|
||||
subject.call(env)
|
||||
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
||||
expect(net_config[:nic_type]).to eq("custom")
|
||||
expect(net_config[:virtualbox__nic_type]).to be_nil
|
||||
end
|
||||
|
||||
it "does not set nic type when namespaced option is set" do
|
||||
machine.config.vm.network 'private_network', { type: 'dhcp', virtualbox__nic_type: "custom" }
|
||||
subject.call(env)
|
||||
_, net_config = machine.config.vm.networks.detect { |type, _| type == :private_network }
|
||||
expect(net_config[:nic_type]).to be_nil
|
||||
expect(net_config[:virtualbox__nic_type]).to eq("custom")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a dhcp private network" do
|
||||
let(:bridgedifs) { [] }
|
||||
let(:hostonlyifs) { [] }
|
||||
|
@ -154,7 +118,7 @@ describe VagrantPlugins::ProviderVirtualBox::Action::Network do
|
|||
mac: nil,
|
||||
name: nil,
|
||||
netmask: "255.255.255.0",
|
||||
nic_type: "virtio",
|
||||
nic_type: nil,
|
||||
type: :dhcp,
|
||||
dhcp_ip: "172.28.128.2",
|
||||
dhcp_lower: "172.28.128.3",
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
require_relative "../base"
|
||||
|
||||
describe VagrantPlugins::ProviderVirtualBox::Action::SetDefaultNICType do
|
||||
include_context "unit"
|
||||
include_context "virtualbox"
|
||||
|
||||
let(:iso_env) do
|
||||
# We have to create a Vagrantfile so there is a root path
|
||||
env = isolated_environment
|
||||
env.vagrantfile("")
|
||||
env.create_vagrant_env
|
||||
end
|
||||
|
||||
let(:machine) do
|
||||
iso_env.machine(iso_env.machine_names[0], :virtualbox).tap do |m|
|
||||
allow(m.provider).to receive(:driver).and_return(driver)
|
||||
end
|
||||
end
|
||||
|
||||
let(:env) {{ machine: machine, ui: machine.ui }}
|
||||
let(:app) { lambda { |*args| }}
|
||||
let(:driver) { double("driver") }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
describe "#call" do
|
||||
let(:provider_config) {
|
||||
double("provider_config",
|
||||
default_nic_type: default_nic_type,
|
||||
network_adapters: network_adapters)
|
||||
}
|
||||
let(:default_nic_type) { nil }
|
||||
let(:network_adapters) { {} }
|
||||
let(:virtualbox_version) { "5.2.23" }
|
||||
|
||||
before do
|
||||
allow(driver).to receive(:version).and_return(virtualbox_version)
|
||||
allow(machine).to receive(:provider_config).and_return(provider_config)
|
||||
end
|
||||
|
||||
it "should call the next action" do
|
||||
expect(app).to receive(:call)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
context "when default_nic_type is set" do
|
||||
let(:default_nic_type) { "CUSTOM_NIC_TYPE" }
|
||||
|
||||
context "when network adapters are defined" do
|
||||
let(:network_adapters) { {"1" => [:nat, {}], "2" => [:intnet, {nic_type: nil}]} }
|
||||
|
||||
it "should set nic type if not defined" do
|
||||
subject.call(env)
|
||||
expect(network_adapters["1"].last[:nic_type]).to eq(default_nic_type)
|
||||
end
|
||||
|
||||
it "should not set nic type if already defined" do
|
||||
subject.call(env)
|
||||
expect(network_adapters["2"].last[:nic_type]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when vm networks are defined" do
|
||||
before do
|
||||
machine.config.vm.network :private_network
|
||||
machine.config.vm.network :public_network, nic_type: nil
|
||||
machine.config.vm.network :private_network, virtualbox__nic_type: "STANDARD"
|
||||
end
|
||||
|
||||
it "should add namespaced nic type when not defined" do
|
||||
subject.call(env)
|
||||
networks = machine.config.vm.networks.map { |type, opts|
|
||||
opts if type.to_s.end_with?("_network") }.compact
|
||||
expect(networks.first[:virtualbox__nic_type]).to eq(default_nic_type)
|
||||
end
|
||||
|
||||
it "should not add namespaced nic type when nic type defined" do
|
||||
subject.call(env)
|
||||
networks = machine.config.vm.networks.map { |type, opts|
|
||||
opts if type.to_s.end_with?("_network") }.compact
|
||||
expect(networks[1][:virtualbox__nic_type]).to be_nil
|
||||
end
|
||||
|
||||
it "should not modify existing namespaced nic type" do
|
||||
subject.call(env)
|
||||
networks = machine.config.vm.networks.map { |type, opts|
|
||||
opts if type.to_s.end_with?("_network") }.compact
|
||||
expect(networks.last[:virtualbox__nic_type]).to eq("STANDARD")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when virtualbox version is has susceptible E1000" do
|
||||
let(:virtualbox_version) { "5.2.22" }
|
||||
|
||||
it "should output a warning" do
|
||||
expect(machine.ui).to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
context "when default_nic_type is set to E1000 type" do
|
||||
let(:default_nic_type) { "82540EM" }
|
||||
|
||||
it "should output a warning" do
|
||||
expect(machine.ui).to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
context "when default_nic_type is set to non-E1000 type" do
|
||||
let(:default_nic_type) { "virtio" }
|
||||
|
||||
it "should not output a warning" do
|
||||
expect(machine.ui).not_to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
context "when network adapter is configured with E1000 type" do
|
||||
let(:network_adapters) { {"1" => [:nat, {nic_type: "82540EM" }]} }
|
||||
|
||||
it "should output a warning" do
|
||||
expect(machine.ui).to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
context "when vm network is configured with E1000 type" do
|
||||
before { machine.config.vm.network :private_network, nic_type: "82540EM" }
|
||||
|
||||
it "should output a warning" do
|
||||
expect(machine.ui).to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
context "when vm network is configured with E1000 type in namespaced argument" do
|
||||
before { machine.config.vm.network :private_network, virtualbox__nic_type: "82540EM" }
|
||||
|
||||
it "should output a warning" do
|
||||
expect(machine.ui).to receive(:warn)
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -43,11 +43,11 @@ describe VagrantPlugins::ProviderVirtualBox::Config do
|
|||
it { expect(subject.gui).to be(false) }
|
||||
it { expect(subject.name).to be_nil }
|
||||
it { expect(subject.functional_vboxsf).to be(true) }
|
||||
it { expect(subject.default_nic_type).to eq("virtio") }
|
||||
it { expect(subject.default_nic_type).to be_nil }
|
||||
|
||||
it "should have one NAT adapter" do
|
||||
expect(subject.network_adapters).to eql({
|
||||
1 => [:nat, {nic_type: "virtio"}],
|
||||
1 => [:nat, {}],
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@ -61,22 +61,6 @@ describe VagrantPlugins::ProviderVirtualBox::Config do
|
|||
end
|
||||
|
||||
it { expect(subject.default_nic_type).to eq(nic_type) }
|
||||
|
||||
it "should set NAT adapter nic type" do
|
||||
expect(subject.network_adapters.values.first.last[:nic_type]).
|
||||
to eq(nic_type)
|
||||
end
|
||||
|
||||
context "when set to nil" do
|
||||
let(:nic_type) { nil }
|
||||
|
||||
it { expect(subject.default_nic_type).to be_nil }
|
||||
|
||||
it "should not set NAT adapter nic type" do
|
||||
expect(subject.network_adapters.values.first.last[:nic_type]).
|
||||
to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#merge" do
|
||||
|
|
|
@ -43,9 +43,10 @@ end
|
|||
|
||||
## Default NIC Type
|
||||
|
||||
By default Vagrant will set the NIC type for all network interfaces to
|
||||
`"virtio"`. If you would rather a different NIC type be used as the
|
||||
default for guests:
|
||||
By default Vagrant will not set the NIC type for network interfaces. This
|
||||
allows VirtualBox to apply the default NIC type for the guest. If you would
|
||||
like to use a specific NIC type by default for guests, set the `default_nic_type`
|
||||
option:
|
||||
|
||||
```ruby
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
|
@ -53,15 +54,6 @@ config.vm.provider "virtualbox" do |v|
|
|||
end
|
||||
```
|
||||
|
||||
or if you would like to disable the default type so VirtualBox's default
|
||||
is applied you can set the value to `nil`:
|
||||
|
||||
```ruby
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.default_nic_type = nil
|
||||
end
|
||||
```
|
||||
|
||||
## Linked Clones
|
||||
|
||||
By default new machines are created by importing the base box. For large
|
||||
|
|
Loading…
Reference in New Issue