sdcardfs如果没有独特的权限控制,只是转发用户态的参数和操作给底层文件系统就没有其存在的意义了。所以接下来关注sdcardfs是如何做到权限控制的。
1. linux的UGO文件权限生成
sdcardfs需要给vfs呈现linux标准的文件权限,即UGO(用户,组,other)权限。同时忽略掉底层文件系统的权限,以达到接管的效果。
首先从inode_operations getattr上看其实如何构造文件权限的。
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
...
err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat);
...
}
static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode,
struct kstat *lower_stat, struct kstat *stat)
{
...
stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, info, top);
stat->nlink = inode->i_nlink;
stat->uid = make_kuid(&init_user_ns, top->d_uid);
stat->gid = make_kgid(&init_user_ns, get_gid(mnt, sb, top));
...
}
大部分的文件都返回一个一致的mode,uid和gid。无论底层文件系统文件的权限是什么,都返回了同样的UGO。
文件权限mode来至于一个get_mode的实现,用户uid取决于top->d_uid,而组gid来自get_gid的实现
static inline int get_mode(struct vfsmount *mnt,
struct sdcardfs_inode_info *info,
struct sdcardfs_inode_data *data)
{
int owner_mode;
int filtered_mode;
struct sdcardfs_vfsmount_options *opts = mnt->data;
int visible_mode = 0775 & ~opts->mask;
...
filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
return filtered_mode;
}
get_mode的内容最重要的是0775 & ~opts->mask。这个opts->mask来至于挂载参数
比如:
/data/media on /storage/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6,derive_gid,default_normal,reserved=20MB)
挂载参数mask是6。因此大部分文件都是呈现为 0775 & ~6 变成0771
a70s:/sdcard $ ls -l
total 120
drwxrwx--x 2 root sdcard_rw 4096 2019-01-01 08:02 Alarms
drwxrwx--x 3 root sdcard_rw 4096 2019-01-01 08:02 Android
drwxrwx--x 2 root sdcard_rw 4096 2019-01-01 08:02 DCIM
drwxrwx--x 3 root sdcard_rw 4096 2019-01-01 08:06 Documents
drwxrwx--x 2 root sdcard_rw 4096 2019-01-01 08:02 Download
drwxrwx--x 2 root sdcard_rw 4096 2019-01-01 08:02 Movies
然后top->d_uid来至于最早挂载文件系统的时候,sdcardfs_read_super
static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb,
const char *dev_name, void *raw_data, int silent)
{
...
if (sb_info->options.multiuser) {
setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
sb_info->options.fs_user_id, AID_ROOT);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
}
...
}
void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
uid_t uid)
{
...
info->data->d_uid = uid;
...
}
得到的结果是AID_ROOT,因此是得到的uid是root用户
而gid的值,由get_gid返回。
static inline int get_gid(struct vfsmount *mnt,
struct super_block *sb,
struct sdcardfs_inode_data *data)
{
...
if (vfsopts->gid == AID_SDCARD_RW && !sbi->options.default_normal)
/* As an optimization, certain trusted system components only run
* as owner but operate across all users. Since we're now handing
* out the sdcard_rw GID only to trusted apps, we're okay relaxing
* the user boundary enforcement for the default view. The UIDs
* assigned to app directories are still multiuser aware.
*/
return AID_SDCARD_RW;
else
return multiuser_get_uid(data->userid, vfsopts->gid);
}
如果挂载参数vfsopts->gid不是AID_SDCARD_RW,1015的话,直接用vfsopts->gid来构造gid的值。vfsopts->gid来至于挂载参数gid
/data/media on /storage/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6,derive_gid,default_normal,reserved=20MB)
这里是1015,因此文件组就是sdcard_rw
在判断文件权限的环境,sdcardfs重写了inode_operation的permission方法,以上面同样的方法构造了一个临时虚拟inode,来做文件判断