sdcardfs之二权限控制

sdcardfs通过运行时构建文件权限,而非直接使用底层文件系统的权限,以实现对UGO(用户,组,other)权限的接管。在挂载时,它使用mask参数动态生成mode,并根据挂载参数构建uid和gid。通过对inode_operations的permission方法的重写,sdcardfs在运行时生成临时虚拟inode进行权限判断。这种设计解决了Android系统中app对sdcard权限控制的复杂需求,通过bind mount和remount策略,实现了动态权限授予,同时减少了内存开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,来做文件判断


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值