原标题:Linux自主访问控制机制模块详细分析之文件系统的扩展属性
2.3.1文件系统的扩展属性2.3.1.1扩展属性
扩展属性是指与文件相关联的“名称/值”对,名称是一个普通的字符串,而值则没有什么限制。为了对属性名进行管理,Linux采用命名空间进行,这些命名空间以宏的形式定义在include/linux/xattr.h中,具体定义如下所示:
/* Namespaces */
#define"os2."
#define(sizeof () - 1)
#define"security."
#define(sizeof () - 1)
#define"system."
#define(sizeof () - 1)
#define"trusted."
#define(sizeof () - 1)
#define"user."
#define(sizeof () - 1)
为了操作扩展属性,内核提供了以下四个系统调用:
(1) setxattr() 用于根据参数来设置或替换某个扩展属性的值,或者创建一个新的扩展属性
(2) getxattr() 用于获取指定扩展属性的值
(3) listxattr() 用于获取文件的扩展属性列表
(4) removexattr() 用于删除指定的扩展属性
对于上述函数,它们还有前缀为l和前缀为f的变体,前缀为l的变体用于对符号链接本身的扩展属性进行操作;前缀为f的变体用于对通过文件描述符指定的文件进行处理。对于这三种类型的系统调用,它们之间唯一的区别在于查找目标对象关联的dentry实例的方式,当找到目标对象对应的目录项之后,它们将会调用相同的函数来进行进一步的处理。下面主要针对setxattr()类系统调用进行分析,对于这些函数,在它们通过相应的方式获得目标对象对应的目录项之后,均会调用setxattr()函数进行进一步的处理。setxattr()函数真正用于根据参数来设置或替换某个扩展属性的值,或者创建一个新的扩展属性,成功执行时返回0;失败时返回相应的错误码。其定义在fs/xattr.c中,函数头如下所示:
static long(struct*, const char*, const void*,
, int)
如上所示,该函数包含五个参数:d指向目标对象对应的目录项;name表示用户空间的扩展属性名;value表示用户空间的扩展属性的值;size表示扩展属性值的长度;flags表示传递给文件系统相关操作的标志。
图2-2 setxattr()函数调用流程图
如图2-2所示,下面结合源码对该函数的执行步骤进行说明:
① 对参数的合法性进行检查。
② 分别调用strncpy_from_user()函数和copy_from_user()函数将参数从用户空间拷贝到内核空间中。
③ 调用vfs_setxattr()函数来实现扩展属性的相关具体操作,对于该函数,下文会进行详细分析。
④ 结束并返回。
对于vfs_setxattr()函数,其定义在fs/xattr.c中,函数头如下所示:
int(struct*, const char *, const void *,,
int)
该函数包含5个参数,参数含义和setxattr()的参数含义基本相同,这里不再赘述。对于该函数,其函数调用流程如图2-3所示,下面结合源码对该函数的执行步骤进行说明:
① 调用xattr_permission()函数来检查用户对指定的文件是否具有写权限,如果有,则返回0,如果没有,vfs_setxattr()函数将会直接返回。
② 调用security_inode_setxattr()函数。该函数实际上只是简单的封装了cap_inode_setxattr()函数,后者用于确定当前进程是否具有修改指定文件扩展属性的权限,若有,则返回0。
③ 如果当前进程可以修改文件的扩展属性,则调用__vfs_setxattr_noperm()函数,该函数在不进行权限检查的情况下执行具体文件系统实现的setxattr()函数来对目标文件的扩展属性进行设置。
④ 结束并返回。
图2-3 vfs_setxattr()函数调用流程图
对于vfs_setxattr()函数调用的两个函数xattr_permission()和__vfs_setxattr_noperm(),下面分别对其进行分析:
1. xattr_permission()
xattr_permission()函数用于判断用户是否可以对指定文件执行指定的操作,若可以,返回0。由于该函数只是根据扩展属性所属的命名空间进行不同的处理,其处理过程比较简单,所以这里直接对其处理过程说明如下:
① 对参数进行判断,如果要对不可修改为文件或只能追加的文件进行写操作,则函数直接返回-EPERM。
② 判断扩展属性是否位于security或system命名空间,若是,则VFS不对其进行限制,而是将扩展属性的判断留给底层文件系统或安全模块,这里直接返回0。
③ 判断扩展属性是否位于trust命名空间,若是,则只有特权用户才能进行访问。
④ 判断扩展属性是否位于user命名空间,若是,则按下述步骤进行处理:
a.判断待访问的文件是否是普通文件或目录,因为只有普通文件和目录才具有扩展属性,若不是,则返回相应的错误码。
b.判断待访问的文件是否是目录、“粘着位”是否置位、当前进程是否是目录的所有者或是由特权用户触发的,并根据判断结果进行相应处理。因为对于“粘着位”置位的目录来说,只有所有者和特权用户才能写入属性。
⑤ 调用inode_permission()函数来判断当前进程对待处理的文件是否具有mask指定的权限,并返回该函数的执行结果。对于该函数的详细分析,详见2.3.4.1小节。
⑥ 结束。
2. __vfs_setxattr_noperm()
__vfs_setxattr_noperm()函数用于在不进行权限检查的情况下执行setxattr操作,函数头如下所示:
int(struct*, const char *,const void *,
,int)
该函数包含5个参数,各参数含义和setxattr()的参数含义基本相同,这里不再赘述。
图2-4 __vfs_setxattr_noperm()函数调用流程图
如图2-4所示,下面结合源码对该函数的执行步骤进行说明:
① 判断要设置的扩展属性是否位于security命名空间,若是,则将issec设为0;反之设为1。
② 判断索引节点所属的文件系统是否实现了setxattr()方法。如果实现,则调用该方法,并对函数执行结果进行判断,如果函数成功执行,则采用inotify机制通知父目录该文件的扩展属性发生变化。
③ 如果索引节点所属的文件系统没有实现setxattr()函数,则接着判断issec变量。如果该变量为真,即指定的扩展属性在security命名空间中,则调用security_inode_setsecurity()函数来进行扩展属性的设置,该函数实际上是由LSM机制提供的,视具体的安全策略而设zhi置。如果其成功执行,则调用inotify机制通知父目录。
④ 结束并返回。
责任编辑: