eCryptfs - mount系统调用
README
- 作者:邢万里
- 学校:重庆邮电大学
- email:wlxing@yahoo.com
入口(系统调用include/linux/syscall.h)
由于安全上的一些问题,2.6和3.x系类的系统调用改动幅度有些偏大。系统调用均经过如下代码进行“过滤”:
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
这里的mount系统调用对应的是SYSCALL_DEFINE5
,而SYSCALL_DEFINEx
实现如下:
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
{ \
__SC_TEST##x(__VA_ARGS__); \
return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))
上述源码对应到mount后如下:
asmlinkage long sys_mount(const char __user * filename, int flags, umode_t mode);
static inline long SYSC_mount(const char __user * filename, int flags, umode_t mode);
asmlinkage long SyS_mount((long)filename, (long)flags, (long)mode)
{
__SC_TEST3(const, char __user * filename, int, flags, umode_t, mode);
return (long)SYSC_mount(const char __user * filename, int flags, umode_t mode);
}
SYSCALL_ALIAS(sys_mount, SyS_mount);
static inline long SYSC_mount(const char __user * filename, int flags, umode_t mode)
这样,很轻易的发现依然存在sys_mount()函数,此函数在源码的include/linux/syscall.h中,但只有声明没有定义。
VFS层(系统调用fs/namespace.c)
如下是mount系统调用对应的具体函数,我这里略去了异常处理和一些其他细节代码,剩余的代码是核心部分。可以很清楚的看到mount系统调用先获得mount参数,并将其传入到do_mount中进行处理。
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data)
{
ret = copy_mount_options(data, &data_page);
ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
(void *) data_page);
}
下述代码依然只保留了核心部分代码。do_mount()
函数先获得挂载点,继而根据flags判断具体的情景:同一个挂载点重复挂载等。最常用的是do_new_mount()
函数。
long do_mount(char *dev_name, char *dir_name, char *type_page,
unsigned long flags, void *data_page)
{
/* ... and get the mountpoint */
retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
else if (flags & MS_BIND)
retval = do_loopback(&path, dev_name, flags & MS_REC);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
retval = do_change_type(&path, flags);
else if (flags & MS_MOVE)
retval = do_move_mount(&path, dev_name);
else
retval = do_new_mount(&path, type_page, flags, mnt_flags,
dev_name, data_page);
}
下述代码依然只保留了核心部分代码。分别进入代码中两个关键函数看看mount如何实现。
static int do_new_mount(struct path *path, char *type, int flags,
int mnt_flags, char *name, void *data)
{
mnt = do_kern_mount(type, flags, name, data);
err = do_add_mount(real_mount(mnt), path, mnt_flags);
}
下述代码依然只保留了核心部分代码。如下do_kern_mount
函数:
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
/* Get the file-system type according to the parameters by parsing the file-system type. Because the file-system-type is
linked, it's effortless to obtain specific type through searching th e list. IF we don't find the file-system, we try
to load kernel module and then search the list again. That is to say, if we do not modprobe fs, but we mount fs, linux can
help us modprobe ecryptfs,then execute mount-operations */
struct file_system_type *type = get_fs_type(fstype);
mnt = vfs_kern_mount(type, flags, name, data);
}
下述代码依然只保留了核心部分代码。以下代码为vfs_kern_mount()
具体实现过程,分为三部分,分配、初始化和mount完成操作。
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
/* Allocate struct mount for fs-type*/
mnt = alloc_vfsmnt(name);
root = mount_fs(type, flags, name, data);
mnt->mnt.mnt_root = root;
mnt->mnt.mnt_sb = root->d_sb;
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
mnt->mnt_parent = mnt;
}
下述代码依然只保留了核心部分代码。以下代码为mount_fs()
函数具体实现,这里可以非常清晰的看到我们要找到的东西已经找到了:type->mount()
,此mount即通过VFS机制具体对应到具体的文件系统,如eCryptfs,从而完成mount真正的、本质上的操作。
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
root = type->mount(type, flags, name, data);
error = security_sb_kern_mount(sb, flags, secdata);
}
eCryptfs层(fs/ecryptfs/main.c)
如下部分的数据结构即为前文说到的VFS机制到具体的文件系统。由.mount
到ecryptfs_mount
,即由VFS到eCryptfs。
static struct file_system_type ecryptfs_fs_type = {
.owner = THIS_MODULE,
.name = "ecryptfs",
.mount = ecryptfs_mount,
.kill_sb = ecryptfs_kill_block_super,
.fs_flags = 0
};
此时只需查询eCryptfs中的ecryptfs_mount()
函数是如何完成具体的挂载操作了。