6.2 以读写模式重新挂载文件系统
一般在挂载文件系统之前,将使用工具fsck检查文件系统的一致性。如果文件系统中存在错误,则fsck会试图修复它们,但是这个过程要求文件系统没有挂载或以只读方式挂载。因此我们在GRUB的配置文件grub.cfg中经常看到内核的命令行参数中有这么一个字串"ro",其是"read only"的简写,目的是告诉内核或initramfs最初以只读方式挂载根文件系统。在Linux系统进入用户空间、使用工具fsck检查文件系统后,然后再以读写方式重新挂载根文件系统。这里我们忽略文件系统检查这一过程,直接以读写模式重新挂载根文件系统。
如果读者没有更改根文件系统中文件的属主和属组为root,那么更新vita系统的/sbin/init程序后,重启系统,我们来检查一下根文件系统是否以读写方式成功挂载了。以笔者的vita系统为例,如图6-1所示。
图 6-1 重新挂载文件系统失败
使用cat命令查看"/proc/mounts",发现根文件系统依然是以只读方式挂载的。使用命令touch试图尝试创建一个文件,创建也以失败告终,再次证明根文件系统确实是以只读方式挂载的。我们手动再次尝试以读写方式重新挂载根文件系统,还是失败了,但是我们看到mount命令提示了一个非常有用的信息:effective UID is 1001。看上去似乎是权限出了问题。mount命令只允许以root的身份进行挂载操作,所以EUID应该是0才对,但是这里的EUID却是1001,这个1001是哪来的呢?
在安装时,安装脚本设置了工具mount和umount的SUID,相关脚本如下:
使用ls命令查看这两个文件的信息可见,SUID确实被设置了:
因此,虽然进程1的EUID是超级用户root,但是一旦执行mount命令时,其EUID将降为vita用户的UID,而在笔者的宿主系统上,vita的UID正是1001,这就是上面"effective UID is 1001"的来源。而mount命令是要求以超级用户root运行的,但是此时进程1被降级为1001,mount命令自然拒绝执行挂载任务。
因此,我们需要修改mount和umount的属主和属组为root,命令如下:
更改属主和属组会导致这两个程序的SUID也会被丢弃,但是对我们来说,这没有什么问题。如果很介意mount和umount的SUID,执行下面的命令重新设置即可:
读者可能会问,第4章在讨论initramfs时,也使用了mount,那时为什么没有这个权限问题?原因是我们在从$SYSROOT复制到那个手工搭建的基本的根文件系统时,SUID被丢弃了。很多有安全要求的领域经常使用SUID这个技巧,比如管理员通常会设置一些网络服务器程序的SUID,这样一旦被人攻破,也不能获得超级用户root的权限。SUID是个比较抽象的概念,通过这个例子,我们切实体验了一次SUID。