是否存在一个始终存在的文件,并且“普通”用户无法对其进行统计?


14

我需要此单元测试。有一个函数对作为其参数传递的文件路径执行lstat。我必须在lstat失败的地方触发代码路径(因为代码覆盖率必须达到90%)

该测试只能在单个用户下运行,因此我想知道Ubuntu中是否存在一个始终存在的文件,但普通用户对该文件或文件夹没有读取权限。(因此lstat除非以超级用户身份执行,否则将失败。)

不存在的文件不是解决方案,因为有一个单独的代码路径已由我触发。

编辑:仅缺少对该文件的读取访问权是不够的。这样lstat仍然可以执行。通过在/ root中创建一个文件夹并在其中创建文件,我能够触发它(在我具有root访问权限的本地计算机上)。并在文件夹上设置权限700。因此,我正在搜索只能由root用户访问的文件夹中的文件。


6
恕我直言/etc/shadow
Romeo Ninov

3
您不能假定存在任何文件,因为您的程序可能在chroot或单独的命名空间中运行。如果假设已经安装了/ proc,并且init没什么特别的,则/proc/1/fd/0应该这样做。
mosvy

1
@mosvy谢谢,这在我的本地计算机上有效。嗯,那我也将在质量检查和暂存池中尝试一下。
蹲着的小猫

2
当您可以只创建一个废弃文件并删除对其的读取访问权限时,为什么要将测试代码与特定类型的OS绑定在一起?
Kilian Foth,

4
我认为一旦它依赖于真实的而非模拟的文件系统,它就不是真正的单元测试。
Toby Speight

Answers:


21

在现代Linux系统上,您应该能够使用/proc/1/fdinfo/0(ID为1的进程的文件描述符1(stdout的信息)(init在应该以as身份运行的root pid命名空间中root)。

您可以使用(作为普通用户)找到一个列表:

sudo find /etc /dev /sys /proc -type f -print0 |
  perl -l -0ne 'print unless lstat'

-type f如果您不想限制为常规文件,请删除)。

/var/cache/ldconfig/aux-cache如果您只需要考虑Ubuntu系统,则是另一个潜在的候选人。它/var/cache/ldconfig只能在大多数GNU系统上正常工作,因为只能通过ldconfigGNU libc附带的命令以root 身份进行读写读写。


1
谢谢!如果/proc/1/fdinfo/0可以在Ubuntu 16.04和18.04上运行,那就足够了。
蹲着的小猫

1
使用/proc/1/fdinfo/0不一定在容器(例如Docker容器)中工作,并且单元测试通常在CI中的此类容器中运行。
菲利普·温德勒

@PhilippWendler,我确实提到了root pid名称空间。OP并不是在问容器,而是在保证Ubuntu系统的文件系统布局中存在的文件。由于容器可以包含任何文件和目录布局,因此该问题无法在那里解决。
—StéphaneChazelas,

12

查看lstat(2)手册页,您会得到一些启发,以防可能因除ENOENT(文件不存在)之外的错误而失败。

最明显的是:

EACCES 搜索权限被拒绝对路径前缀的目录之一的路径

因此,您需要一个无法搜索的目录。

是的,您可以查找系统中已经/var/lib/private存在的一个(也许它已经存在?),但是您也可以自己创建一个,等效于:

$ mkdir myprivatedir
$ touch myprivatedir/myunreachablefile
$ chmod 0 myprivatedir
$ ls -l myprivatedir/myunreachablefile

lstat(2)操作将在此处以EACCES失败。(从目录中删除所有权限可确保这样做。也许您甚至不需要那么多,而chmod -x删除执行权限就足够了,因为访问目录下的文件需要目录的执行权限。)

看看lstat(2)的手册页,还有另一种创造性的方法:

ENOTDIR 路径前缀的组成部分路径不是目录。

因此,尝试访问诸如之类的文件/etc/passwd/nonexistent将触发此错误,此错误又与ENOENT(“无此类文件或目录”)不同,并且可能满足您的需求。

另一个是:

ENAMETOOLONG 路径太长。

但是您可能需要为此输入一个非常长的名称(我相信4,096字节是典型的限制,但是您的系统/文件系统可能有一个更长的名称。)

最后,很难说出其中任何一项对您实际上是否有用。您说您想要某种不会触发“文件不存在”方案的方案。尽管通常意味着ENOENT错误,但实际上,许多更高级别的检查将把lstat(2)中的任何错误简单地解释为“不存在”。例如,test -e或者[ -e ...]来自shell 的等效内容可能只是将以上所有内容解释为“不存在”,尤其是因为它没有返回不同错误消息的好方法,并且不返回错误意味着文件已经存在,绝对不是这样。


@StephaneChazelas很好!更新。
filbranden

6

你可以find自己做。

/etc-配置文件目录为起点:

sudo find /etc -type f -perm 0400 -user root

在我的系统上,这不返回任何内容。

您可以限制较少并允许组root(仅用户root应是group的成员root),并注意以下权限440

sudo find /etc -perm 0440 -user root -group root

在我的系统上,返回:

/etc/sudoers.d/README
/etc/sudoers

编辑:

根据您的编辑,您正在寻找一个目录,该目录没有足够的权限来允许调用用户阻止目录列表:

sudo find / -perm o-rwx -type d -user root -group root 

在这里,我要查找的目录(-type d)缺少其他人(o-rwx)的读写执行perm位,并且由拥有root:root

从技术上讲,仅缺少execute(x)位会阻止目录lstat(2)在目录上列出()。

/run/systemd/inaccessible/基于Systemd init的系统上找到的输出中。

关于文件/proc/sys/dev

  • 这些文件系统是虚拟FS,即它们驻留在内存中,而不在磁盘上

  • 如果您打算依靠/proc,请使用/proc/1/PID之下的某种东西,即依靠它,因为没有保证以后的PID(进程)不存在,所以没有任何以后的PID具有可靠性/一致性。


谢谢,我想我的问题是错的。我仍然可以lstat文件,而无需对其进行读取访问。也许必须限制对文件夹的访问?(我修改了标题)
蹲下的小猫

谢谢。随着find / -type d -perm 0400 -user root我已经找到了目录/proc/20/map_files/,如果我指的是一个虚构的文件名,文件夹内,像/proc/20/map_files/asdasd,那么它总是失败。该文件夹在Ubuntu上是否始终存在?
蹲着的小猫,

@CrouchingKitten,其中的目录/proc/1/可能更安全,因为init始终存在。但这proc不是常规的文件系统,以防万一。
ilkkachu

谢谢,我/proc/1/fdinfo/0投了赞成票,但接受了其他答案,因为他说可以保证可以在现代Ubuntu上使用。
蹲着的小猫,

-perm o-rwx就像-perm 0,所有位都从头开始。在这里,你想要! -perm -1
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.