Restrict synced folder access to DrvFs file systems only within WSL
This commit is contained in:
parent
1f99da7a11
commit
859d48d5f5
|
@ -483,6 +483,41 @@ module Vagrant
|
|||
path.to_s.start_with?(wsl_windows_accessible_path.to_s)
|
||||
end
|
||||
|
||||
# Mount pattern for extracting local mount information
|
||||
MOUNT_PATTERN = /^(?<device>.+?) on (?<mount>.+?) type (?<type>.+?) \((?<options>.+)\)/.freeze
|
||||
|
||||
# Get list of local mount paths that are DrvFs file systems
|
||||
#
|
||||
# @return [Array<String>]
|
||||
def wsl_drvfs_mounts
|
||||
if !defined?(@_wsl_drvfs_mounts)
|
||||
@_wsl_drvfs_mounts = []
|
||||
if wsl?
|
||||
result = Util::Subprocess.execute("mount")
|
||||
result.stdout.each_line do |line|
|
||||
info = line.match(MOUNT_PATTERN)
|
||||
if info && info[:type] == "drvfs"
|
||||
@_wsl_drvfs_mounts << info[:mount]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@_wsl_drvfs_mounts
|
||||
end
|
||||
|
||||
# Check if given path is located on DrvFs file system
|
||||
#
|
||||
# @param [String, Pathname] path Path to check
|
||||
# @return [Boolean]
|
||||
def wsl_drvfs_path?(path)
|
||||
if wsl?
|
||||
wsl_drvfs_mounts.each do |mount_path|
|
||||
return true if path.to_s.start_with?(mount_path)
|
||||
end
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
# If running within the Windows Subsystem for Linux, this will provide
|
||||
# simple setup to allow sharing of the user's VAGRANT_HOME directory
|
||||
# within the subsystem
|
||||
|
|
|
@ -3,6 +3,7 @@ require "securerandom"
|
|||
require "set"
|
||||
|
||||
require "vagrant"
|
||||
require "vagrant/action/builtin/mixin_synced_folders"
|
||||
require "vagrant/config/v2/util"
|
||||
require "vagrant/util/platform"
|
||||
require "vagrant/util/presence"
|
||||
|
@ -757,6 +758,33 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
# If running from the Windows Subsystem for Linux, validate that configured
|
||||
# hostpaths for synced folders are on DrvFs file systems, or the synced
|
||||
# folder implementation explicitly supports non-DrvFs file system types
|
||||
# within the WSL
|
||||
if Vagrant::Util::Platform.wsl?
|
||||
# Create a helper that will with the synced folders mixin
|
||||
# from the builtin action to get the correct implementation
|
||||
# to be used for each folder
|
||||
sf_helper = Class.new do
|
||||
include Vagrant::Action::Builtin::MixinSyncedFolders
|
||||
end.new
|
||||
folders = sf_helper.synced_folders(machine, config: self)
|
||||
folders.each do |impl_name, data|
|
||||
data.each do |_, fs|
|
||||
hostpath = File.expand_path(fs[:hostpath], machine.env.root_path)
|
||||
if !Vagrant::Util::Platform.wsl_drvfs_path?(hostpath)
|
||||
sf_klass = sf_helper.plugins[impl_name.to_sym].first
|
||||
if sf_klass.respond_to?(:wsl_allow_non_drvfs?) && sf_klass.wsl_allow_non_drvfs?
|
||||
next
|
||||
end
|
||||
errors["vm"] << I18n.t("vagrant.config.vm.shared_folder_wsl_not_drvfs",
|
||||
path: fs[:hostpath])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Validate sub-VMs if there are any
|
||||
@__defined_vms.each do |name, _|
|
||||
if name =~ /[\[\]\{\}\/]/
|
||||
|
|
|
@ -1794,6 +1794,10 @@ en:
|
|||
be an array of options.
|
||||
shared_folder_requires_guestpath_or_name: |-
|
||||
Shared folder options must include a guestpath and/or name.
|
||||
shared_folder_wsl_not_drvfs: |-
|
||||
The host path of the shared folder is not supported from WSL. Host
|
||||
path of the shared folder must be located on a file system with
|
||||
DrvFs type. Host path: %{path}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Translations for commands. e.g. `vagrant x`
|
||||
|
|
|
@ -589,6 +589,79 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
|||
sf = subject.synced_folders
|
||||
expect(sf["my-vagrant-folder"][:guestpath]).to be_nil
|
||||
end
|
||||
|
||||
context "WSL host paths" do
|
||||
let(:valid_path){ "/mnt/c/path" }
|
||||
let(:invalid_path){ "/home/vagrant/path" }
|
||||
let(:synced_folder_impl){ double("synced_folder_impl", new: double("synced_folder_inst", usable?: true)) }
|
||||
let(:fs_config){ double("fs_config", vm: double("fs_vm", allowed_synced_folder_types: nil)) }
|
||||
let(:plugin){ double("plugin", manager: manager) }
|
||||
let(:manager){ double("manager", synced_folders: {sf_impl: [synced_folder_impl, 1]}) }
|
||||
|
||||
let(:stub_pathname){ double("stub_pathname", directory?: true, relative?: false) }
|
||||
|
||||
before do
|
||||
allow(Pathname).to receive(:new).and_return(stub_pathname)
|
||||
allow(stub_pathname).to receive(:expand_path).and_return(stub_pathname)
|
||||
allow(Vagrant::Util::Platform).to receive(:wsl?).and_return(true)
|
||||
allow(Vagrant::Util::Platform).to receive(:wsl_drvfs_path?).with(valid_path).and_return(true)
|
||||
allow(Vagrant::Util::Platform).to receive(:wsl_drvfs_path?).with(invalid_path).and_return(false)
|
||||
allow(machine).to receive(:config).and_return(fs_config)
|
||||
allow(Vagrant).to receive(:plugin).with("2").and_return(plugin)
|
||||
subject.synced_folder(".", "/vagrant", disabled: true)
|
||||
end
|
||||
|
||||
it "is valid when located on DrvFs" do
|
||||
subject.synced_folder(valid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
|
||||
it "is invalid when not located on DrvFs" do
|
||||
subject.synced_folder(invalid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_invalid
|
||||
end
|
||||
|
||||
context "when synced folder defines support for non-DrvFs" do
|
||||
let(:support_nondrvfs){ true }
|
||||
|
||||
before do
|
||||
allow(synced_folder_impl).to receive(:respond_to?).with(:wsl_allow_non_drvfs?).and_return(true)
|
||||
allow(synced_folder_impl).to receive(:wsl_allow_non_drvfs?).and_return(support_nondrvfs)
|
||||
end
|
||||
|
||||
context "and is supported" do
|
||||
it "is valid when located on DrvFs" do
|
||||
subject.synced_folder(valid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
|
||||
it "is valid when not located on DrvFs" do
|
||||
subject.synced_folder(invalid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "and is not supported" do
|
||||
let(:support_nondrvfs){ false }
|
||||
|
||||
it "is valid when located on DrvFs" do
|
||||
subject.synced_folder(valid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
|
||||
it "is invalid when not located on DrvFs" do
|
||||
subject.synced_folder(invalid_path, "/guest/path")
|
||||
subject.finalize!
|
||||
assert_invalid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#usable_port_range" do
|
||||
|
|
|
@ -357,5 +357,53 @@ describe Vagrant::Util::Platform do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".wsl_drvfs_mounts" do
|
||||
let(:mount_output) { <<-EOF
|
||||
rootfs on / type lxfs (rw,noatime)
|
||||
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,noatime)
|
||||
proc on /proc type proc (rw,nosuid,nodev,noexec,noatime)
|
||||
none on /dev type tmpfs (rw,noatime,mode=755)
|
||||
devpts on /dev/pts type devpts (rw,nosuid,noexec,noatime)
|
||||
none on /run type tmpfs (rw,nosuid,noexec,noatime,mode=755)
|
||||
none on /run/lock type tmpfs (rw,nosuid,nodev,noexec,noatime)
|
||||
none on /run/shm type tmpfs (rw,nosuid,nodev,noatime)
|
||||
none on /run/user type tmpfs (rw,nosuid,nodev,noexec,noatime,mode=755)
|
||||
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noatime)
|
||||
C: on /mnt/c type drvfs (rw,noatime)
|
||||
EOF
|
||||
}
|
||||
|
||||
before do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with("mount").
|
||||
and_return(Vagrant::Util::Subprocess::Result.new(0, mount_output, ""))
|
||||
end
|
||||
|
||||
it "should locate DrvFs mount path" do
|
||||
expect(subject.wsl_drvfs_mounts).to eq(["/mnt/c"])
|
||||
end
|
||||
|
||||
context "when no DrvFs mounts exist" do
|
||||
let(:mount_output){ "" }
|
||||
|
||||
it "should locate no paths" do
|
||||
expect(subject.wsl_drvfs_mounts).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".wsl_drvfs_path?" do
|
||||
before do
|
||||
expect(subject).to receive(:wsl_drvfs_mounts).and_return(["/mnt/c"])
|
||||
end
|
||||
|
||||
it "should return true when path prefix is found" do
|
||||
expect(subject.wsl_drvfs_path?("/mnt/c/some/path")).to be_truthy
|
||||
end
|
||||
|
||||
it "should return false when path prefix is not found" do
|
||||
expect(subject.wsl_drvfs_path?("/home/vagrant/some/path")).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue