计算机系统工程SecFs实验一
前言
这个学期(大二下)我在郝xd的撺掇下,选了曲老师的《计算机系统工程》这门课。对标的是MIT的6.033课程,参考内容目录MIT6.033 Computer System Design | 计算机系统设计 | Miigon’s blog
这门课在国内各大高校同类型的课基本找不到(可能不叫这个名字吧),就连这本课本的中译版正版都很难找到(我只买到了盗版)。就是这么一门神秘的课程,却讲了许多计算机系统设计的基本原则,可谓是干货满满。用曲老师的话来说:这门课可能是大学四年中,计算机专业最实用的课。在上了半个学期后,我是深深体会到了。故想写一篇博客记录一下这节课的实验课,以及自己的一些想法。
实验背景
世界正在慢慢变得更加紧密,并且越来越需要让你的所有数据都具有可用性、可共享性、安全性和可 复制性,由于这些需求,Dropbox 和 Google Drive 等云服务应运而生,并取得了巨大成功。他们获取你的 文件并将它们透明地托管在“云”中。但是,用户在此过程中失去了对数据的一些控制。你必须信任公司 能够保证数据安全;你必须相信他们不会查看你的数据,不会共享它,也不会丢失它。在本实验中,要求 开发一个文件系统,这个系统允许用户将数据存储在远程文件服务器上,但是用户无需信任该服务器。
实验介绍
本实验的目的是让你了解如何构建安全、相对复杂且有用的软件。你将构建一个远程文件系统 SecFS, 它在面对完全不受信任的服务器时能提供机密性和完整性。 我们为你提供了一个具有很少功能和更少安全保证的框架为基础进行本实验。你需要扩展这些功能来 实现线面的实验目标。我们提供的代码是 SUNDR 序列化版本的一部分。你应该阅读论文 SUNDR ,因为本 实验中的许多概念和原理与之相似。为了完成本实验,你需要实现其余部分以支持整个序列化 SUNDR,并 添加机密性保证(文件的读取保护)。
实验官网:6.858 Spring 2020 Final assignment (mit.edu)
实验内容
环境配置
本实验需要python3环境,这还是有点坑爹的。
1 | apt-get install -y python3-venv libfuse-dev python3-dev |
然后克隆SecFS文件系统的仓库,并安装
1 | git clone https://github.com/mit-pdos/secfs-skeleton.git secfs |
出现以下提示即说明安装成功,之后只需要使用start.sh即可启动文件系统
文件目录
代码预览
./secfs/access.py
1 | import secfs.fs |
./secfs/crypto.py
1 | # 该文件实现了SecFS的加密部分 |
./secfs/fs.py
1 | # 该文件实现了inode级别的文件系统操作。 |
./secfs/tables.py
1 | # 此文件包含处理 i 映射的解析和修改的所有代码。 这包括组句柄间接和 VSL 验证,因此该文件有些毛茸茸(?)。 |
./secfs/types.py
1 | class Principal: |
./secfs/store/block.py
1 | # 该文件处理与SecFS服务器的blob存储的所有交互。 |
./secfs/store/inode.py
1 | import pickle |
./secfs/store/tree.py
1 | # 该文件提供了操作SecFS中的目录的功能。 |
实验任务
(1)Enable file/directory creation
在文件 secfs/fs.py 中,有一个名为create 的方法,它负责在文件系统中创建新文件和目录,并负责分 配和配置 inode,然后将其存储在服务器上,为新文件设置适当的 i,并将其链接到其父目录。如果你打开 这个文件,你会发现有一部分代码缺失了,缺失的部分用了一个大的 FIXME 注释块标识,解释丢失的代码 应该做什么。
在补写代码之前,你将无法创建新文件或目录,即使是 root,但可以查找现有文件或目录(例如.users 或.groups)。因此,从这里开始我们的实验。
为了补写代码,你首先应该尝试理解 secfs.tables.modmap 函数,这个函数修改 i-tables 将 i 映射为块哈 希。这是 SecFS 的关键函数,并在整个代码中广泛使用。要添加.和 ..,你应该查看 secfs.store.tree.add 函 数, 然后为了链接最后的 i,你将用到 secfs.fs.link 函数 (或者是 link,link 和create 在同一个文件中)。要 在服务器上存储数据,你需要使用相对简单的 secfs.store.block.store 函数。
成功实施_create 后,你应该能在文件系统的根目录中以 root 身份创建新文件和目录。
In the file
secfs/fs.py
, there is a function called_create
. It is used to create new files and directories in the file system, and is responsible for allocating and configuring an inode, storing it on the server, setting up an appropriatei
for the new file, and linking it into its parent directory. If you open it up, you will see that a chunk of the code is missing, denoted by a largeFIXME
comment block explaining what the missing code is supposed to do.Until this code is filled in, you will be unable to create new files or directories, even as root, but looking up existing ones will work as expected (e.g.
.users
or.groups
). This is therefore a natural place to start your implementation.In order to write this code, you should first try to build a cursory understanding of the
secfs.tables.modmap
function, which modifies thei
-tables that mapi
s to block hashes. This is a critical component of SecFS, and is used extensively throughout the code. For adding.
and..
, you should look atsecfs.store.tree.add
, and for linking in the finali
, you will need to usesecfs.fs.link
(or justlink
since_create
is in the same file). To store data on the server, you will also need to use the relatively straightforwardsecfs.store.block.store
. You may findsecfs.fs.init
a useful starting point.When you have implemented
_create
successfully, you should be able to create new files and directories as root in the root of the file system. You may also have to come back to this function when you implement multi-user support in Exercise 2 below.
(2)Multi-client support
你可能已经注意到,在出现第二个客户端之前可以正常运行 test.sh。当第二个客户端尝试访问已挂载 文件系统中的任何文件时,会出现错误:
1 | LookupError: asked to resolve i ((0,False),0), but i does not exist |
出现错误是因为第二个客户机没有访问文件系统的 i-tables,因为它们目前只存储在第一个客户机的内 存中。在 SUNDR 中,这些 i-tables 被持久保存在服务器上,通过对描述文件系统的版本结构(或 VSes)更 改 i 来更改对用户和组的 i-tables 。这些文件从服务器下载,然后用于验证本地下载的 i-tables。当文件系 统被更改时,一个新的、已签名的 VS 被上传到服务器,以便其他客户端可以看到更改。
具体来说,实验任务 2 是为了能够在单独的挂载点上启动第二个 SecFS 客户机,并能够运行命令 ls -la 来显示.users 和.groups 的文件。要完成本实验,你必须用 SUNDR 的版本结构列表替换 secfs/tables.py 中的 current_itables 映射,该映射将用户和组句柄映射到文件哈希(参见论文的第 3.3.2 节)。这个列表必须与 服务器通信,以便其他客户机可以下载它,然后使用这些映射来探索文件系统。
当你可以使用第二个客户机读取文件系统中的文件时,尝试在一个客户机中创建几个文件(以root身份), 并验证在另一个客户机挂载后运行 ls 时该文件是否出现。
As you may have noticed, running
test.sh
works fine until a second client appears. When this second client attempts to access any file in the mounted file system, an error is given:
1 LookupError: asked to resolve i ((0, False), 0), but i does not existThis happens because the second client does not have access to the file system’s
i
-tables, since these are (currently) only stored in the memory of the first client. In SUNDR, thesei
-tables are persisted on the server, and changes to thei
-tables of users and groups are announced through Version Structures (or VSes) that describe changes to the file system. These are downloaded from the server, verified, and then used to verify downloadedi
-tables locally. When the file system is changed, a new, signed VS is uploaded to the server, so that other clients can see the change.Specifically, your goal for the first exercise is to be able to start a second SecFS client (see “Interacting with the file system”) on a separate mount point, and be able to run
ls -la
to reveal the.users
and.groups
files. To do so, you will have to replace thecurrent_itables
map insecfs/tables.py
, which maps user and group handles to file hashes, with SUNDR’s Version Structure List (see section 3.3.2 of the paper). This list must be communicated to the server so that other clients can download it, and then use those mappings to explore the file system.You may want to first get the list working, and only afterwards add cryptographic signing and verification of the VSes. You should consider implementing your cryptographic operations in
secfs/crypto.py
. Public keys for users are available insecfs.fs.usermap
(key is aUser
).When you can read files in the file system using a second client, try to create a few file (as root) in one client, and verify that this file then appears when running
ls
in the other client’s mountpoint.
实验提示
实验中会用到 SUNDR 论文中的内容。我们在此处给出了从 SUNDR 论文中的图 2 和图 3 到 SecFS 中 文件的映射:
structure | location |
---|---|
i-tables | secfs/tables.py |
inodes | secfs/store/inode.py |
directory block | secfs/store/tree.py |
version structure | has not been implemented, but should probably replace current_itables in secfs/tables.py |
参考文献:inode.pdf——主要介绍了inode和i-table的关系
实验一步骤
先讲实验一,首先,由之前讲命名的那堂课可以知道,从文件名到磁盘上的块实现访问,需要经过十层间接层,中间就有一层是inode层。我们都知道,一个inode对应一个文件,且每个inode都有一个结点编号,元信息和指向块的指针。这几乎囊括了一个文件的所有信息。
这样我们只需要知道一个目录下有多少个inode编号,就可以知道有多少文件了,如何去高效的查找inode,这就用到了i-table,存有目录下的inode编号。
SUNDR使用i-handle来查找某个用户的i-table,这和实验一关系不大,所以略过不讲。
先来看需要补充的函数上方的init函数
可以看到,首先先给Inode结点分配了ihash,然后给这个ihash建立一个映射给root_i;这个实验主要操作的数据对象就是这个I类型,这个类型是由principal和i-number组成的。
这里的root_i对应的是根目录,因为一个目录下,无论如何都会有两个.和..
这两个目录,用于指向父目录和自己,所以同时也需要创建两个文件。这里使用的add方法,也无需了解其实现,只要知道怎么用的就行了,大概就是将某个I对象映射到某个目录下,并起个名字。
这里在获得new_ihash之后,为什么要使用一个modmap映射呢?乍一看这里写的很抽象,我们知道,modmap作用是建立ihash的映射,并且返回一个I对象,这里并没有返回值,这是为什么呢?
其实这是modmap函数的另一个用法,修改i-table里i-number到ihash的映射,因为文件或目录被修改之后,需要重新生成一个ihash,add函数就是给目录增加文件的同时,返回了最新的ihash。
然后就到users
和groups
文件的生成了,文件的生成和目录是差不多的,主要是少了一步add的步骤。还多了一步link,我们都知道,在Linux文件系统中,文件的只有在连接数为0的时候才会删除,也就是说,增加连接数才会让一个文件出现(?大概)
综上,实验一的参考代码如下:
实验二前瞻
反反复复看了好多遍实验一和SUNDR,才大概知道实验二要干嘛,我觉得吧,实验二主要是操作current_itables,让不同用户使用自己i-table,还有就是当文件修改后,要及时更新ihash且上传服务器,还有就是版本向量啥的,总之方向大概是这样。