Linux内核源代码情景分析-访问权限与文件安全性

在Linux内核源代码情景分析-从路径名到目标节点,一文中path_walk代码中,err = permission(inode, MAY_EXEC)当前进程是否可以访问这个节点,代码如下:

int permission(struct inode * inode,int mask)

{

if (inode->i_op && inode->i_op->permission) {

int retval;

lock_kernel();

retval = inode->i_op->permission(inode, mask);

unlock_kernel();

return retval;

}

return vfs_permission(inode, mask);

}

在ext2_read_inode中,i_op可以设置为ext2_file_inode_operations,ext2_dir_inode_operations,ext2_fast_symlink_inode_operations,page_symlink_inode_operations,均没有permission指针。所以执行vfs_permission,代码如下:

int vfs_permission(struct inode * inode,int mask)

{

int mode = inode->i_mode;

if ((mask & S_IWOTH) && IS_RDONLY(inode) &&

(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))

return -EROFS; //如果要求的写文件,并且是只读系统,而且是常规文件,目录,或者链接时,返回-EROFS,表示不能访问

if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) //Nobody gets write access to an immutable file

return -EACCES;

if (current->fsuid == inode->i_uid)//如果当前进程的fsuid和inode结构的i_uid相等,那么应该比较mode中S_IRUSR、S_IWUSR、S_IXUSR位

mode >>= 6;

else if (in_group_p(inode->i_gid))//如果当前进程的fsgid和inode结构的i_gid相等,那么应该比较mode中S_IRGRP、S_IWGRP、S_IXGRP位

mode >>= 3;

if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))//mask相当于要求,mode是现有的当前用户可以访问的权限,如果相等就返回0。假如不相等,如果当前进程得到了授权,允许其CAP_DAC_OVERRIDE,即可以凌驾于文件系统的访问权限控制机制DAC之上。

return 0;

/* read and search access */

if ((mask == S_IROTH) ||

(S_ISDIR(inode->i_mode) && !(mask & ~(S_IROTH | S_IXOTH))))

if (capable(CAP_DAC_READ_SEARCH))

return 0;

return -EACCES;

}

其中mask为:

#define MAY_EXEC 1

#define MAY_WRITE 2

#define MAY_READ 4

inode->i_mode为:

用于对三种不同用户的访问权限:

#define S_IRWXU 00700

#define S_IRUSR 00400

#define S_IWUSR 00200

#define S_IXUSR 00100

#define S_IRWXG 00070

#define S_IRGRP 00040

#define S_IWGRP 00020

#define S_IXGRP 00010

#define S_IRWXO 00007

#define S_IROTH 00004

#define S_IWOTH 00002

#define S_IXOTH 00001

参考这张图就好理解了。

还有三个标志位,是一个状态占一个位:

#define S_ISUID 0004000 #define S_ISGID 0002000 #define S_ISVTX 0001000

现在16位只剩下4位了,表示文件类型,要为每种文件类型都分配一个标志位就不够了,所以表示文件的类型的这4位是编码的。

#define S_IFMT 00170000

#define S_IFSOCK 0140000

#define S_IFLNK 0120000

#define S_IFREG 0100000

#define S_IFBLK 0060000

#define S_IFDIR 0040000

#define S_IFCHR 0020000

#define S_IFIFO 0010000

capable,代码如下:

static inline int capable(int cap) { #if 1 /* ok now */ if (cap_raised(current->cap_effective, cap)) #else if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0) #endif { current->flags |= PF_SUPERPRIV; return 1; } return 0; } #define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag)) #define cap_t(x) (x) #define CAP_TO_MASK(x) (1 << (x))

current->cap_effective是在sys_execve->do_execve->prepare_binprm初始设置的。

int prepare_binprm(struct linux_binprm *bprm)

{

int mode;

struct inode * inode = bprm->file->f_dentry->d_inode;

mode = inode->i_mode;

/* Huh? We had already checked for MAY_EXEC, WTF do we check this? */

if (!(mode & 0111))/* with at least _one_ execute bit set */

return -EACCES;

if (bprm->file->f_op == NULL)

return -EACCES;

bprm->e_uid = current->euid;

bprm->e_gid = current->egid;

if(!IS_NOSUID(inode)) {

/* Set-uid? */

if (mode & S_ISUID)

bprm->e_uid = inode->i_uid;

/* Set-gid? */

/*

* If setgid is set but no group execute bit then this

* is a candidate for mandatory locking, not a setgid

* executable.

*/

if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))

bprm->e_gid = inode->i_gid;

}

/* We don't have VFS support for capabilities yet */

cap_clear(bprm->cap_inheritable);

cap_clear(bprm->cap_permitted);

cap_clear(bprm->cap_effective);

/* To support inheritance of root-permissions and suid-root

* executables under compatibility mode, we raise all three

* capability sets for the file.

*

* If only the real uid is 0, we only raise the inheritable

* and permitted sets of the executable file.

*/

if (!issecure(SECURE_NOROOT)) {

if (bprm->e_uid == 0 || current->uid == 0) {

cap_set_full(bprm->cap_inheritable);

cap_set_full(bprm->cap_permitted);

}

if (bprm->e_uid == 0)

cap_set_full(bprm->cap_effective);//这里设置的

}

memset(bprm->buf,0,BINPRM_BUF_SIZE);

return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);

原文发布于微信公众号 - 马哥Linux运维(magedu-Linux)

原文发表时间:2016-10-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术小黑屋

Android性能调优利器StrictMode

作为Android开发,日常的开发工作中或多或少要接触到性能问题,比如我的Android程序运行缓慢卡顿,并且常常出现ANR对话框等等问题。既然有性能问题,就需...

1702
来自专栏转载gongluck的CSDN博客

第16章 非阻塞式I/O

执行时间:         停等版本(完全阻塞)  》  select加阻塞I/O版本  》  fork多进程版本(Linux下多线程也应该差不多)  》  非...

3376
来自专栏杨建荣的学习笔记

11g备库无法开启ADG的原因分析 (r7笔记第62天)

今天碰到一个有些奇怪的问题,但是奇怪的现象背后都是有本质的因果。 下午在做一个环境的检查时,发现备库是在mount阶段,这可是一个11gR2的库,没有ADG实在...

3844
来自专栏xingoo, 一个梦想做发明家的程序员

套接字选项

选项影响套接字操作,如 封包路由,OOB数据传输,获取和设置套接字选项分别是 getsockopt  setsockopt 用法如下: int getsocko...

1906
来自专栏二次元

Linux下安装PHP环境

2441
来自专栏atom

国内最好的破解软件下载站整理

2.5K6
来自专栏哈雷彗星撞地球

iOS下WebRTC音视频通话(二)-局域网内音视频通话准备开始着手开发接收方

这里是iOS 下WebRTC音视频通话开发的第二篇,在这一篇会利用一个局域网内音视频通话的例子介绍WebRTC中常用的API。 如果你下载并编译完成之后,会看...

3972
来自专栏Android Note

Android – 在Gradle中更改APK文件名

1735
来自专栏蓝天

__lll_mutex_lock_wait的错误原因

运行下面的代码,即可重现上面的__lll_mutex_lock_wait()问题:

2594
来自专栏运维

FreeBSD9.0加速ports的升级速度

ports从网上下载软件包自动安装,那么从那里下载呢?首先,我们需要安装axel来取代默认的下载工具fetch,这样可以提高ports的安装速度:   cd /...

1362

扫码关注云+社区

领取腾讯云代金券