您的位置:首页 > 运维架构 > Linux

linux内核权限控制之vfs_permission分析

2016-03-06 09:03 363 查看
在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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息