1、文件
Linux的文件包括一般文件和目录。
文件包括inode节点和block节点集。
inode节点存储文件的元数据,具体有
1)The size of the file in bytes.
2)Device ID (this identifies the device containing the file).
3)The User ID of the file's owner.
4)The Group ID of the file.
5)The file mode which determines the file type and how the file's owner, its group, and others can access the file.
6)Additional system and user flags to further protect the file (limit its use and modification).
7)Timestamps telling when the inode itself was last modified (ctime, inode change time), the file content last modified (mtime, modification time), and last accessed (atime, access time).
8)A link count telling how many hard links point to the inode.
9)Pointers to the disk blocks that store the file's contents (see inode pointer structure).
针对一般文件,block节点存储一般文件的具体数据
针对目录,block节点存储多条<filename,inodeid>形式的数据,其中filename是目录下子文件的文件名,inodeid是相应的inode节点的id
2、inode
inode节点中存储的是文件的元数据,相对于block节点存储文件的具体数据来说,这些元数据主要用来进行文件控制。有两个元数据需要特别强调
1)ctime,mtime,atime
ctime:inode change time,指的是最后修改inode节点中元数据的时间
mtime:modification time,指的是最后修改block节点中数据的时间
atime:access time,指的是最后访问block节点中数据的时间
2)权限
用于配置不同用户群体(文件拥有者,文件所属组组用户,其他用户)对文件的操作权限,其实真正意义上是指对文件的block节点内容的操作权限
3、权限详解
文件一般有r,w,x三种权限,对于一般文件和目录来说,这3种权限的含义是不同的。
1)一般文件
i)r
是否能够读取block节点中的内容
ii)w
是否能够修改block节点中的内容
iii)x
是否能够执行block节点中的内容
2)目录
i)r
是否允许读取block节点中以<filename,inodeid>形式存储的记录中的filename
ii)w
是否允许增加,删除和修改block节点中<filename,inodeid>形式的记录
iii)x
是否允许读取block节点中以<filename,inodeid>形式存储的记录中的inodeid,并且加载inodeid对应的inode节点,并且能够读取和修改inode节点中的元数据
4、权限的应用场景
上述的权限只是文件的inode节点上元数据的一部分,是静态的。权限的应用场景是这样的:
一个进程想要操作某个文件,文件系统首先获得该进程的<有效用户:有效用户组>的身份组合,然后跟该文件的inode节点上元数据中的权限配置进行比对,获取到该进程对该文件所允许的操作权限,如果进程对文件的操作在这个权限允许范围内,那么就可以顺利运行,否则,由于缺少权限被禁止运行
5、权限具体判定过程
下面介绍一些具体的权限判定过程,也分为一般文件和目录两种情况。
1)一般文件
i)读取:r
一个进程想要读取一个一般文件的过程如下:
首先,文件系统获得进程的<有效用户:有效用户组>身份组合,然后判断该身份组合对该文件所在的目录是否具有x权限,只有具有该x权限,才能加载该一般文件的inode节点,并读取inode节点上的元数据,包括权限配置信息
接着,比对进程的<有效用户:有效用户组>身份组合和该一般文件的权限配置信息,看是否具有对该一般文件的r权限,如果有,可读取;否则,不可读取
举例子说明,假设有一个目录authority,它的权限配置是"--x------",它的拥有者是dsl,该目录下有一个文件a.txt,它的权限配置是"r--------",它的拥有者也是dsl,此时以dsl作为有效用户运行的一个进程想要读取a.txt的内容,文件系统首先获取进程的有效用户是dsl,然后发现它对authority具有x权限,因而可以加载a.txt文件的inode节点,inode节点上的元数据和元数据中的权限配置信息,从这个权限配置信息中,文件系统发现配置了dsl用户对该文件具有r权限,而现在进程的有效用户就是dsl,因此可以顺利读取文件内容
ii)修改:w
一个进程想要修改一个一般文件的过程如下:
首先,文件系统获得进程的<有效用户:有效用户组>身份组合,然后判断该身份组合对该文件所在的目录是否具有x权限,只有具有该x权限,才能加载该一般文件的inode节点,并读取inode节点上的元数据,包括权限配置信息
接着,比对进程的<有效用户:有效用户组>身份组合和该一般文件的权限配置信息,看是否具有对该一般文件的w权限,如果有,可修改;否则,不可修改
iii)执行:x
一个进程想要执行一个一般文件的过程如下:
首先,文件系统获得进程的<有效用户:有效用户组>身份组合,然后判断该身份组合对该文件所在的目录是否具有x权限,只有具有该x权限,才能加载该一般文件的inode节点,并读取inode节点上的元数据,包括权限配置信息
接着,比对进程的<有效用户:有效用户组>身份组合和该一般文件的权限配置信息,看是否具有对该一般文件的x权限,如果有,可执行;否则,不可执行
2)目录
i)读取:r
一个进程想要读取一个目录的过程如下:
首先,文件系统获得进程的<有效用户:有效用户组>身份组合,然后判断该身份组合对该目录所在的父目录是否具有x权限,只有具有该x权限,才能加载该目录的inode节点,并读取inode节点上的元数据,包括权限配置信息
接着,比对进程的<有效用户:有效用户组>身份组合和该目录的权限配置信息,看是否具有对该目录的r权限,如果有,可读取;否则,不可读取
注意,如果只有对目录的读取权限,那么只能看到<filename,inodeid>记录中的filename信息,而不能加载inodeid对应的inode节点,也就不能得到inode节点上的元数据
ii)修改:w
一个进程想要修改一个目录的过程如下:
首先,文件系统获得进程的<有效用户:有效用户组>身份组合,然后判断该身份组合对该目录所在的父目录是否具有x权限,只有具有该x权限,才能加载该目录的inode节点,并读取inode节点上的元数据,包括权限配置信息
接着,比对进程的<有效用户:有效用户组>身份组合和该目录的权限配置信息,看是否具有对该目录的wx权限,如果有,可修改;否则,不可修改
注意,如果只有对目录的w权限,那么不能实现修改。
修改本质上就是对<filename,inodeid>记录的增加,删除和修改,修改一般也就是重命名
增加的情况,至少得加载inode节点,修改ctime,那么得有x权限
删除的情况,至少得加载inode节点,减少inode节点上的硬链接计数,那么得有x权限
修改(重命名)的情况,Linux下的重命名是通过先建立硬链接,然后再删除原先的硬链接方式实现的,那么至少得加载inode节点,改变inode节点上的硬链接计数,那么得有x权限
因此,要达到修改目录的目标,进程的<有效用户:有效用户组>必须拥有对目录的wx权限
iii)执行:x
目录的x权限没有显式效果,作为辅助用途
6、特殊权限
1)SUID
i)一般文件上设置SUID
当一个设置了SUID位的可执行文件被执行时,该文件将以文件所有者的身份运行,如果所有者是root,那么将以root的身份来执行该文件,即最后得到的进程的有效用户是root,在这种情况下效果与sudo执行一个文件一致[不过两者的Real UserId和Real GroupId并不一致,前者的<Real UserId:Real GroupId>是<dsl:dsl>,这里以dsl代表进程创建用户,dsl是dsl用户的primary group,后者的<Real UserId:Real GroupId>是<root:root>]
可通过以下代码来进行测试
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("%d", geteuid());
return 0;
}
> gcc -o setuid-test setuid-test.c
> ./setuid-test
备注:基于安全策略,在linux中,只能对二进制文件设置SUID,而不能对包括脚本文件在内的其他可执行文件设置SUID
ii)目录上设置SUID
The SUID permission set on a directory is ignored on UNIX and Linux systems.
2)SGIT
i)一般文件上设置SGIT
当在一个可执行文件上设置了SGIT之后,那么文件执行创建得到的进程的有效用户组是该一般文件的所属组
可以用以下代码来测试有效用户组
#include<stdio.h>
#include<unistd.h>
int main(int argc,char** argv)
{
printf("%d\n",getegid());
return 0;
}
ii)目录上设置SGIT
当在一个目录A上设置了SGIT之后,在该目录下创建的的一般文件和目录的所属组跟A的所属组一致
3)sticky-bit
i)一般文件上设置sticky-bit
When set, it instructed the operating system to retain the text segment of the program in swap space after the process exited. This speeds up subsequent executions by allowing the kernel to make a single operation of moving the program from swap to real memory.
ii)目录上设置sticky-bit
当在一个目录A上设置了sticky-bit之后,在该目录下创建的一般文件和目录具有这样的一个特殊性质:
只有它们(一般文件和目录)的属主和root用户有权删除它们,其他任何用户即便拥有对A目录的rwx权限,也不可以删除它们
最典型的例子是:
tmp目录是所有用户共有的临时文件夹,所有用户都拥有读写权限,这就必然出现一个问题,A用户在/tmp里创建了文件a.file,此时B用户看了不爽,在/tmp里把它给删了(因为拥有读写权限),那肯定是不行的。实际上是不会发生这种情况,因为有特殊权限sticky-bit权限,正如drwxrwxrwt中的最后一个t
7、权限失效的场景
如上所述,上面这些权限是对针对block节点内容的操作的控制机制,即这些权限不能对针对inode节点元数据内容的操作进行控制。
比如执行chmod等命令得到的进程对文件inode节点元数据内容的操作就不能由上述权限进行控制,这就引出了另外一个控制机制:文件拥有者和root用户。
执行chmod等命令得到的进程,只有该进程的有效用户是文件拥有者或者root的时候,它才能对文件进行操作。
但是,需要注意的是,要对文件的inode节点的元数据内容进行修改,首先要加载inode节点才行,即进程的<有效用户:有效用户组>需要具有文件所在目录的x权限才行,这点跟上述的控制机制是一致的
8、其他
另外像chown,chgrp这两个涉及到多个用户的操作,只能以root的用户身份进行,其他用户都没有跨用户的权限
参考文献:
[1]http://blog.csdn.net/dslztx/article/details/45973283
[2]http://www.linuxquestions.org/questions/linux-software-2/rename-and-ctime-913753/