概述
在Linux系统中,需要对文件所在目录有读写权限和可执行权限,才可以删除文件。读写权限很好理解,因为需要读取和修改文件夹内容信息。而可执行权限感觉有点奇怪,谷歌+分析内核源码,得到答案。
测试
注意:需要使用普通用户进行以下操作
首先使用mkdir
创建一个目录,查看其权限,为drwxr-xr-x
(755)
然后在该目录下创建文件,查看权限为-rw-r--r--
(644)
可以看到文件夹和文件的默认权限是不同的,文件夹具有可执行权限
使用chmod命令设置文件夹权限为600,使用ls
命令列出文件,或者rm
直接删除文件,都提示权限不足。(要删除的话首先要列出文件,合理)
使用chmod命令设置文件夹权限为100,使用cd
命令(通过chdir
这一系统调用),正常打开该目录,但无法列出文件。
由此可知,chdir
仅检测可执行权限,不检测读权限。而列出文件则需要读和可执行权限。
r:列出文件夹下的文件名(其他信息则需要x)
x:切换该目录为工作目录
探究
为什么需要可执行权限
见Unix File and Directory Permissions and Modes
Because directories are not used in the same way as regular files, the permissions work slightly (but only slightly) differently. An attempt to list the files in a directory requires read permission for the directory, but not on the files within. An attempt to add a file to a directory, delete a file from a directory, or to rename a file, all require write permission for the directory, but (perhaps surprisingly) not for the files within. Execute permission doesn’t apply to directories (a directory can’t also be a program). But that permission bit is reused for directories for other purposes.
Execute permission is needed on a directory to be able to cd into it (that is, to make some directory your current working directory).
Execute is needed on a directory to access the inode information of the files within. You need this to search a directory to read the inodes of the files within. For this reason the execute permission on a directory is often called search permission instead.
You can think of read and execute on directories this way: directories are data files that hold two pieces of information for each file within, the file’s name and it’s inode number. Read permission is needed to access the names of files in a directory. Execute (a.k.a. search) permission is needed to access the inodes of files in a directory, if you already know the file’s name.
文件夹的可执行权限被用于chdir,也用于访问目录内文件的inode信息(因此对于文件夹而言,可执行权限通常被称为搜索权限)
源码分析
rm源码
rm
是GNU coreutils里的一个命令,源码见:
remove.c
最终调用excise
函数删除文件
1 | /* Remove the file system object specified by ENT. IS_DIR specifies |
可以看到是通过unlinkat
系统调用删除文件(也可使用strace
跟踪系统调用)
内核源码
其中定义了unlinkat
和unlink
系统调用:
1 | SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) |
删除文件时,是调用do_unlinkat
函数,跟踪内部第一个函数filename_parentat
的调用链:path_parentat
-link_path_walk
-may_lookup
-inode_permission
调用inode_permission
时传入了MAY_EXEC
,如下:
1 | static inline int may_lookup(struct user_namespace *mnt_userns, |
其中MAY_EXEC
定义于include/linux/fs.h
1 |
|
可以看到是通过调用inode_permission
函数,对可执行权限进行判断,代码如下:
1 | int inode_permission(struct user_namespace *mnt_userns, |
查看do_inode_permission
1 | static inline int do_inode_permission(struct user_namespace *mnt_userns, |
最终调用generic_permission
:
1 | int generic_permission(struct user_namespace *mnt_userns, struct inode *inode, |
看到注释Searching includes executable on directories, else just read.
(具体是不是这里检测,并不是非常确定,还有待进一步调试内核)
PS:capable_wrt_inode_uidgid
函数用于判断用户是否具有忽略DAC访问限制的能力,详见[转载] Linux的capability深入分析
CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制
CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制
参考
Difference between executable directory vs executable files
What permissions are needed to delete a file in unix?
Where can i get the source code of rm command
Linux删除文件过程解析
[转载] Linux的capability深入分析