linux内核权限控制之vfs_permission分析

在linux文件系统的各种操作里,很重要的一个东西就是权限控制,我们来一起追溯内核源代码,弄清楚内核的权限之谜。
在VFS(linux虚拟文件系统)里,权限控制都是通过vfs_permission来实现的,我们从vfs_permission来看,vfs_permission函数定义在fs/namei.c,定义如下
int vfs_permission(struct nameidata *nd, int mask)
{
	return permission(nd->dentry->d_inode, mask, nd);
}

vfs_permission函数直接调用了permission函数,我们进入permission函数看看。permission函数定义在fs/namei.c,定义如下
int permission(struct inode *inode, int mask, struct nameidata *nd)
{
	/*得到文件的权限*/
	umode_t mode = inode->i_mode;
	int retval, submask;


	if (mask & MAY_WRITE) {


		/*只读文件系统不可以写入*/
		if (IS_RDONLY(inode) &&
		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
			return -EROFS;


		/*不可修改文件不能写*/
		if (IS_IMMUTABLE(inode))
			return -EACCES;
	}




	/*对于普通文件的MAY_EXEC需要可执行权限,如果文件系统不可以执行,就返回错误*/
	if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) ||
			(nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC))))
		return -EACCES;


	/* 一般的权限程序不理解MAY_APPEND*/
	submask = mask & ~MAY_APPEND;
	/*如果inode的函数操作结构体有permission函数,就调用这个函数*/
	if (inode->i_op && inode->i_op->permission)
		retval = inode->i_op->permission(inode, submask, nd);
	else
		/*否则就调用通用的权限检查函数*/
		retval = generic_permission(inode, submask, NULL);
	if (retval)
		return retval;
	/*安全操作,最后决定是否有权限,调用内核自己注册的security_ops结构体的函数,新的内核特性*/
	return security_inode_permission(inode, mask, nd);
}

接下来进入generic_permission函数看一看通用的权限检查函数的实现。generic_permission函数定义在fs/namei.c,定义如下
/**
 * generic_permission  -  在POSIX系列操作系统检察权限
 * @inode:	检察权限需要的inode
 * @mask:	权限检查(%MAY_READ, %MAY_WRITE, %MAY_EXEC)
 * @check_acl:	回调函数,我们传入的是NULL,不必考虑
 */
int generic_permission(struct inode *inode, int mask,
		int (*check_acl)(struct inode *inode, int mask))
{
	umode_t			mode = inode->i_mode;
	/*所有者的权限*/
	if (current->fsuid == inode->i_uid)
		mode >>= 6;
	else {
		if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
			int error = check_acl(inode, mask);
			if (error == -EACCES)
				goto check_capabilities;
			else if (error != -EAGAIN)
				return error;
		}
		/*如果对于组ID检查成功,就右移三位*/
		if (in_group_p(inode->i_gid))
			mode >>= 3;
	}
	/*自主控制位检查*/
	if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))
		return 0;


 check_capabilities:
	/*DAC权限检查*/
	if (!(mask & MAY_EXEC) ||
	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
		if (capable(CAP_DAC_OVERRIDE))
			return 0;


	/*
	 * Searching includes executable on directories, else just read.
	 */
	if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
		if (capable(CAP_DAC_READ_SEARCH))
			return 0;


	return -EACCES;
}

你可能感兴趣的:(c,linux,kernel,内核,文件系统)