wsl ubuntu拒绝访问_一起聊聊WSL的那些事儿(下)

 

前文回顾:一起聊聊WSL的那些事儿(上)

90e1154dbb614eaad8086790e6ce2b64.png

文件系统

       在WSL这个feature刚出来的时候,很多人都抢着装上了这个特性,包括笔者的同学们都争先恐后的体验这个特性,不过最后都成了黑子,因为大家发现File IO 在WSL中实在是太慢了。

cc11c58ae2250b4bcfa4a94b76ddbc8f.png

* Picture 14 笔者在自己用vmware中的ubuntu和wsl 尝试解压同一个文件的差距

       为了更好的介绍WSL进行了哪些操作,从而实现了Linux向Windows文件系统的兼容(同时却也没有很好的解决File IO问题),这里需要简单介绍一下Linux和Windows上对文件管理的接口,帮助大家理解。

90e1154dbb614eaad8086790e6ce2b64.png

Linux - VFS

        Linux中使用了一种中抽象的虚拟文件系统,叫做VFS。它定义了一套接口让Linux上的应用能够调用对底层的磁盘文件系统中的文件进行操作,例如读写,打开等等,并且通过定义接口让不同的上层操作系统来实现对应的接口,从而实现将整个底层的文件系统抽象出来。

       在VFS中,使用了如下列举的几种特性:

       Inode 这个结构体中存储了各种linux下的文件中被VFS使用的基本数据结构。比如说普通文件,符号文件,设备文件等等。每一个inode代表的是一个文件对象(而非文件名),里面主要记录的是文件关于存储的信息。

       Directories entry存储的是每一个目录,存放了指向每一个inode的指针,并且这个对象会被存储在内存中,加快访问文件inode的速度。

       File Object 这个是inode中通过open的方式获取的真实的文件对象,其中记录了文件对象在应用层面的相关信息,里面记录当前文件读/写指针,以及针对当前文件中定义的读写等各类操作。

     File descriptors Linux也是实现了类似于Windows下的handle管理对象,通过对文件描述符的操作来实现对文件的管理。

90e1154dbb614eaad8086790e6ce2b64.png

Windows

       Windows下的所有系统资源都是以对象的形式存在的。除了文件外,还包括线程,共享内存,计时器等。打开文件的操作其实就等价于打开NT kernel下的对象管理器,通过I/O管理器将当前的请求发送到正确的文件系统驱动中。因为在Windows中,不存在inode这样的结构体,不过Windows中存在Directory entry这样的结构,所以其会通过ntfs.sys这类驱动来解决路劲解析问题。

       当文件被打开的时候,对象管理器将会创捷一个文件对象。与Linux中的文件描述符相对应,Windows中的称为句柄(Handles),句柄对应的是一个内核对象(Kernel Object)而不是文件描述符(File Descriptor)。当调用类似于NtReadFile 这类API去读取文件的死后,I/O 管理器将会创建一个IRP,发送至文件系统驱动,让文件对象能够执行请求。由于Windows下没有类似于inode的结构体,所以很多的文件请求都需要一个文件对象来完成。

90e1154dbb614eaad8086790e6ce2b64.png

WLS下的内部实现

       可以看到,Windows和Linux下对于文件的操作存在很多不同的地方,所以Windows为了尽可能的实现Linux的文件操作,实现了一套VFS*相关的接口,模仿Linux中提出VFS来兼容底层文件系统的方式,实现了一个类似文件操作接口。

      对于文件描述符的系统调用(比如read, write或者 sync),lxcore直接调用文件系统定义的相应操作。这个系统有意的使用近似Linux行为,从而WSL可以支持相同的语义。

9b9e385f78cc8361058d062ae9a64433.png

* Picture 15 WSL下的类VFS文件系统(图片来自网络)

       如上图, Procfs和Sysfs这些是直接实现的一些抽象,因为在Windows下并没有类似的文件结构。不过除去这些,有两个驱动是专门处理文件存储的,一个是用于处理WSL根目录下文件存储的VolFs,另一个是处理现有的分卷上文件存储的Drvfs。

90e1154dbb614eaad8086790e6ce2b64.png

VolFs

        VolFs是用来挂载虚拟文件系统(VFS)的根目录的处理驱动,使用%LocalAppData%\lxss\rootfs作为备用存储器。其主存储放在                                          【C:\Users\Username\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_*\LocalState】

不过由于文件系统的差异,所以如果直接使用Windows直接操作(非WSL环境下)创建的文件权限可能会有问题。。

      Linux和Windows的文件系统有好几个方面的不同。所以VolFs必须对Windows不能直接支持的几个Linux特性提供支持。例如,由于Windows 中没有索引节点概念,VolFs 创建的索引节点会关联要给Windows 文件对象句柄。这些句柄的打开不需要任何的读/写文件,且只能用于元数据的请求。

5499d6eaf16d08d44f269c7165d0431a.png

* Picture 16 Inode中间其实维护了一个File Handle

      Windows本身可以处理大小写敏感。正如前面提到的,Windows和NTFS实际上支持大小写敏感操作,所以,无论全局注册键如何控制,VolFs会请求对象管理器将路径看做是大小写敏感的。所以,切记不要再根目录以外的地方用WSL创建同名但是大小写不同的文件,这样对于Windows的文件管理会出现不可预计的后果。

       Linux的文件名还支持将全部字符视为合法字符。NT中却有更多的限制,有些字符根本不允许作为文件名,还有些字符可能具有特殊含义(例如“:”表示数据流)。为了支持所有Linux文件名,VolFs将文件名中的非法字符进行转义。

       Linux中的断开链接(unlinking)和重命名(renaming)有一些不同的语义。具体的说,某个文件即使有打开着的文件描述符指向它,也可以断开链接。同样,某个文件即使打开着,也可以对其进行重命名的操作。在Windows中,如果要请求删除一个文件,那它最终的状态必须是关闭着的,此时文件名在文件系统中可见。为了支持Linux中的断开链接语义,请求删除前,VolFs会将断开链接的文件重命名至一个隐藏的临时文件夹中。

       Linux的索引节点具有一些Windows中不存在的属性,包括拥有者和组、文件模式等。这些属性存储在与磁盘文件相关联的NTFS扩展属性中。扩展属性中存储的信息如下:

· 模式(Mode):包括文件类型(普通文件、符号链接、FIFOs等)和该文件的权限位。

· 拥有者(Owner):拥有该文件的Linux用户ID和组ID。

· 设备ID(Device ID):设备文件的主设备号和次设备号。注意,WSL目前还不允许用户在VolFs中创建设备文件。

· 文件时间(File times):Linux中的文件访问时间、修改时间和改变时间所采用的格式和粒度与Windows中不同,所以,这些时间也存储在EAs(Extended Attributes)中。

       其余的索引节点属性,例如索引节点号和文件大小, 都源自于NTFS中保存的信息。

       所以,如果从Windows下直接操作一些WSL下的文件,就会导致很多这些基本信息未被更新到Volfs中,从而导致权限出现错乱。

90e1154dbb614eaad8086790e6ce2b64.png

Drvfs

       为了便于和Windows系统之间文件存储的交互,WSL使用了DrvFs文件系统。WSL将具有可支持文件系统的卷自动挂载到/mnt目录中,例如/mnt/c、/mnt/d等。目前,仅能支持NTFS和ReFs两种类型的卷标。

       DrvFs的操作方式和VolFs类似。当创建索引节点和文件对象时,打开指向Windows文件的句柄。但与VolFs相比,DrvFs遵循Windows规则。比如,DrvFs使用Windows权限,只允许使用合法的NTFS文件名;并且DrvFs不支持特殊的文件类型,比如FIFOs(命名管道)和sockets。

       在DrvFs中,当打开一个文件时,会继承启动WSL的用户令牌的Windows权限,也就是说令牌是由用户执行bash.exe产生的。所以,在WSL中要访问C:\Windows目录下的文件,在bash环境中使用“sudo”还是不行的,虽然你拥有了root权限,但并没有改变你的Windows用户令牌,还必须启动bash.exe以便进一步获得合适的权限。

       为了给用户关于他针对某个文件所拥有的权限的提示,DrvFs检查用户有效的文件权限,并将其转换成“读/写/可执行”位,例如执行“ls -l”命令可以看到。不过这其中也并不都是一对一的映射关系。例如,Windows中对于在目录中创建文件和子目录需要不同的权限。如果用户拥有任意一种权限,DrvFs都视为对目录拥有写访问权限,但实际上有些操作可能还是会因拒绝访问而失败。

6a285709100cc5fce14ac42da9e603af.png

* Picture 17 Drvfs尽可能的实现了一一映射

      因为对文件的有效访问权限会因bash.exe是否启动是否提升了权限而不同,所以,DrvFs中显示的文件权限也会随着bash实例的权限提升与否而改变。

      DrvFs支持区分大小写文件,这意味着可以创建两个文件名大小写不同的DrvFs。请注意,许多的Windows应用程序可能无法处理这种情况,并且可能无法打开一个或两个文件。(比如笔者测试的平台为1709,如果将两个exe文件改成同名但是大小写不同,会导致双击的时候两个软件都无法启动)。

e02721a87cacd98b15bd8e7c9b5c0ba7.png

* Picture 18 哦......WSL和Windows打架了

      大小写敏感被禁用在卷根上,但其它地方可以用。因此,为了使用大小写敏感的文件。不要尝试创建/mnt/c,而是创建一个目录,在这个目录里可以创建文件。

      和VolFs不同,DrvFs不会存储任何的额外信息。相反,所有的索引节点属性都是通过查询NT中使用的文件属性、有效权限以及其它的信息派生而来的。DrvFs还禁用了目录项缓存,以确保即使Windows进程对目录的内容进行了修改的情况下,它也总能提供正确的、最新的信息。因此,当使用DrvFs时,对Windows进程如何处理文件没有任何限制。

       DrvFs还对文件使用了Windows删除语义,所以,如果某个文件存在任何打开着的文件描述符(或者Windows进程在处理着),那我们就不能取消对其的链接。

f0cfbb8f0359847e36be5047a08ac27b.png

* Picture 19 导致WSL File IO慢的原因之一

       回到本段开头提到的问题,为什么说WSL的File IO很慢呢?其实通篇看下来的话应该也猜到原因了:因为WSL只是简单的实现了Windows 文件系统的抽象,所以WSL的File IO慢,其实本质上是Windows的文件系统和Linux的文件系统的差异导致的。笔者做的实验中,使用的是一个目录很深并且有很多小文件的压缩包,对于这类量非常大的小文件处理,Windows本身就弱于Linux,这就导致了问题本身的出现。(当然,Windows Defender的扫描也是需要背锅的原因之一)

90e1154dbb614eaad8086790e6ce2b64.png

WSL一些现存的问题

       虽然WSL目前设计以及趋于完善,不过本身却还有不少有问题的地方。比如说,目前所有的WSL中的进程再Windows操作系统中都是直接运行在内核态的,虽然这个进程本身是由Linux进行维护,不过一旦出现之前提到的那种CVE,直接使用攻击手法对lxcore翻译过程进行攻击,这个过程就会变得像是沙箱逃逸一样,对Windows本身的内核产生影响。

       WSL中的elf以及其依赖的各类library在load的时候是没有设置SEC_IMAGE这个flag的,这意味着一些Windows的一些API和feature将会无法追踪这个image的映射过程。例如PsSetLoadImageNotifyRoutine将会无法追踪相关的elf映射这将导致一些杀毒软件的监控失效,并且AppLocker(AppLocker是Microsoft Windows 7操作系统引入的应用程序白名单技术)将会无法工作。并且其操作是强制大小写敏感的(除非在WSL的Linux中关闭这个特性),所以它能够绕过Windows中的注册表开关,强行执行大小写敏感。

90e1154dbb614eaad8086790e6ce2b64.png

WSL2

0a9a373e679320b8e84f11d9bb7464ca.png

* Picture 20 WSL还没研究完呢又来了个WSL2

       笔者在研究WSL的过程中遇到了蛮多的麻烦,在研究有了一些眉目的时候,BUILD2019宣布WSL2公布了。此时内心是十分复杂的。

        随着6月13号WSL2的公布,很多爱好者也体验到了其中的特性。这里简单介绍一下WSL2中与WSL里不相同的部分:

1.     WSL2并非直接翻译Linux的内核中断调用,而是使用了类似虚拟机的技术。过去微软是通过将Linux的各种中断,文件系统等进行翻译,从而对Linux系统进行一个抽象。但是实际上这样做还是有很多的问题,直译这个过程中,有些内容,例如linux下的namespace,systemd,以及VBF+EXT4向NTFS的转型其实还是非常不便的。而新推出的WSL2则是会直接在Windows中内嵌一个Linux的内核,版本是4.19,一个LTS版本的Linux 内核版本。如果是Linux的内核的话,那就意味着不再需要lx*的内核驱动对中断/文件系统的各种映射进行翻译,能够原生的支持Linux下的各类中断调用。

2.     WSL依然会保留,并且可以和WSL2可以切换,甚至可以同时运行两种不同的WSL

3.     由于是一种轻量级的VM,其依赖于Hyper-v的内核,开启WSL2的时候,会与VBox和Vmware这类软件发生冲突

4.     WSL2使用了VHDX来存储根目录,从而让WSL2使用EXT4+VFS的文件系统,尽可能的和真正的Linux相符。

       总的来说,WSL2目前已经出现了很多的新特性,但是好像还有不少问题(比如说不能调用GPU等相关硬件)目前还在开发中,之后的特性就让我们拭目以待吧。

参考网站:

http://www.alex-ionescu.com/publications/BlueHat/bluehat2016.pdf

https://devblogs.microsoft.com/commandline/announcing-wsl-2/

https://blogs.msdn.microsoft.com/wsl/

https://devblogs.microsoft.com/commandline/whats-new-for-wsl-in-windows-10-version-1903/

*以上部分图片来自网络

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值