chroot "no such file or directory" 打印错误丢失的文件
chroot "no such file or directory" prints wrong missing file
我知道类似的问题在这里被问了十亿次,但与我让我的系统正常工作的问题不同。当我破坏它时,我只是收到了错误的错误消息(我想使用这些调试另一个问题,所以它们的工作至关重要)。
从工作系统开始:
$ tree
.
├── bin
│ └── bash
├── lib
│ ├── libc.so.6
│ ├── libdl.so.2
│ └── libtinfo.so.6
└── lib64
└── ld-linux-x86-64.so.2
$ sudo chroot . /bin/bash
bash-5.0#
正如我们所期望的那样 运行 bash 和 bash 运行s.
现在,当我删除 lib
文件夹中的任何内容时,我收到一条错误消息,提示我缺少该库:
$ rm -f lib/libdl.so.2
$ sudo chroot . /bin/bash
/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory
也符合预期。但是,当我删除 lib64
文件夹中的 ld-linux-x86-64.so.2
时:
$ rm -f lib64/ld-linux-x86-64.so.2
$ sudo chroot . /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
它告诉我 /bin/bash
不见了。该消息与我实际删除时完全相同。
$ rm -f bin/bash
$ sudo chroot . /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
所以出于某种原因,它认为 bash 丢失了,而实际上,我认为是动态链接器丢失了。我认为这是因为它首先使用此链接器加载小精灵,但这并不能使消息更正确。
我什至在我实际阻止 bash
它通过 运行 在 qemu
中找到 ld-linux-x86-64.so.2
时进行了检查 在不同的系统上 我得到了正确的错误消息:
<some arm system>$ qemu-x86_64 -L /tmp/nowhere bin/bash
/lib64/ld-linux-x86-64.so.2: No such file or directory
这是一个错误吗?是否有一些选项可以告诉 chroot
不要这样做并打印实际丢失的文件?这个文件有什么魔力吗?这是怎么回事?
TLDR:为什么 chroot
告诉我缺少可执行文件,而实际上 lib64/ld-linux-x86-64.so.2
是?
Why does chroot
tell me the executable is missing when actually
lib64/ld-linux-x86-64.so.2
is?
假设您正在使用来自 GNU coreutils 的 chroot
程序,我们可以查看代码以了解发生了什么(希望“魔法”会消失)。这里是 github mirror of chroot.c.
如果我们在错误消息 failed to run command
中搜索字符串,我们会立即找到打印它的(唯一)代码行:
/* Execute the given command. */
execvp (argv[0], argv);
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
error (0, errno, _("failed to run command %s"), quote (argv[0]));
return exit_status;
}
如您所见,它是在 execvp()
系统调用之后打印的。 execvp()
是允许执行程序的系统调用(的一种变体)(在您的情况下为 /bin/bash
)。如果程序执行成功,execvp()
不会 return 因为:
The exec()
family of functions replaces the current process image with a new process image.
it returns only 以防出现错误并适当设置 errno
。
代码然后检查 errno
以确定退出状态:
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
最后打印错误:
error (0, errno, _("failed to run command %s"), quote (argv[0]));
如您所见,argv[0]
总是 在 failed to run command
之后打印(/bin/bash
在您的情况下,即它试图 exec
在 chroot 环境中使用。
errno
是由 execvp()
错误编号“returned”并确定之后打印的内容(error()
在我的系统上定义如下):
/* Print a message with `fprintf (stderr, FORMAT, ...)';
if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
extern void error (int __status, int __errnum, const char *__format, ...)
No such file or directory
是错误编号 ENOENT
并且在以下情况下被 execvp()
和朋友“returned”:
ENOENT The file pathname or a script or ELF interpreter does not exist.
(“ELF解释器”是动态链接器的同义词I guess)
chroot
实际上不知道 真正 出了什么问题,它只能报告 execvp()
在 errno
中输入的内容,我认为这就是错误含糊不清且有点误导的原因。
Why does chroot tell me the executable is missing when actually lib64/ld-linux-x86-64.so.2 is?
可执行文件本身不是 运行。
它类似于 shell 脚本 - 你有 #!/bin/sh
并且文件有可执行权限,所以你 ./file
它真的 运行s /bin/sh ./file
.
当您执行 ./file
并且文件是带有 PT_INTERP
的 ELF 文件时,来自 PT_INTERP
header 的文件被获取并且是 运行。所以真正发生的是,你真的 运行ning /lib64/ld-linux-x86-64.so.2 ./file
为(几乎)你系统上的每一个可能的可执行文件。您可以在您的系统上执行此操作 - /lib64/ld-linux-x86-64.so.2 /bin/bash
将 运行 Bash.
所以内核读取 /bin/bash
,看到它是一个 ELF 文件,读取 PT_INTERP
,然后 运行s /lib64/ld-linux-x86-64.so.2
。因为 /lib64/ld-linux-x86-64.so.2
不存在,内核将 errno
设置为 ENOENT
.
然后 chroot
程序检查 errno
,并打印消息 printf("Failed to run command <that command>: <error description>
。 chroot
不知道内核找不到程序解释器或可执行文件本身,它不知道。 chroot
只打印错误描述。
我知道类似的问题在这里被问了十亿次,但与我让我的系统正常工作的问题不同。当我破坏它时,我只是收到了错误的错误消息(我想使用这些调试另一个问题,所以它们的工作至关重要)。
从工作系统开始:
$ tree
.
├── bin
│ └── bash
├── lib
│ ├── libc.so.6
│ ├── libdl.so.2
│ └── libtinfo.so.6
└── lib64
└── ld-linux-x86-64.so.2
$ sudo chroot . /bin/bash
bash-5.0#
正如我们所期望的那样 运行 bash 和 bash 运行s.
现在,当我删除 lib
文件夹中的任何内容时,我收到一条错误消息,提示我缺少该库:
$ rm -f lib/libdl.so.2
$ sudo chroot . /bin/bash
/bin/bash: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory
也符合预期。但是,当我删除 lib64
文件夹中的 ld-linux-x86-64.so.2
时:
$ rm -f lib64/ld-linux-x86-64.so.2
$ sudo chroot . /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
它告诉我 /bin/bash
不见了。该消息与我实际删除时完全相同。
$ rm -f bin/bash
$ sudo chroot . /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
所以出于某种原因,它认为 bash 丢失了,而实际上,我认为是动态链接器丢失了。我认为这是因为它首先使用此链接器加载小精灵,但这并不能使消息更正确。
我什至在我实际阻止 bash
它通过 运行 在 qemu
中找到 ld-linux-x86-64.so.2
时进行了检查 在不同的系统上 我得到了正确的错误消息:
<some arm system>$ qemu-x86_64 -L /tmp/nowhere bin/bash
/lib64/ld-linux-x86-64.so.2: No such file or directory
这是一个错误吗?是否有一些选项可以告诉 chroot
不要这样做并打印实际丢失的文件?这个文件有什么魔力吗?这是怎么回事?
TLDR:为什么 chroot
告诉我缺少可执行文件,而实际上 lib64/ld-linux-x86-64.so.2
是?
Why does
chroot
tell me the executable is missing when actuallylib64/ld-linux-x86-64.so.2
is?
假设您正在使用来自 GNU coreutils 的 chroot
程序,我们可以查看代码以了解发生了什么(希望“魔法”会消失)。这里是 github mirror of chroot.c.
如果我们在错误消息 failed to run command
中搜索字符串,我们会立即找到打印它的(唯一)代码行:
/* Execute the given command. */
execvp (argv[0], argv);
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
error (0, errno, _("failed to run command %s"), quote (argv[0]));
return exit_status;
}
如您所见,它是在 execvp()
系统调用之后打印的。 execvp()
是允许执行程序的系统调用(的一种变体)(在您的情况下为 /bin/bash
)。如果程序执行成功,execvp()
不会 return 因为:
The
exec()
family of functions replaces the current process image with a new process image.
it returns only 以防出现错误并适当设置 errno
。
代码然后检查 errno
以确定退出状态:
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
最后打印错误:
error (0, errno, _("failed to run command %s"), quote (argv[0]));
如您所见,argv[0]
总是 在 failed to run command
之后打印(/bin/bash
在您的情况下,即它试图 exec
在 chroot 环境中使用。
errno
是由 execvp()
错误编号“returned”并确定之后打印的内容(error()
在我的系统上定义如下):
/* Print a message with `fprintf (stderr, FORMAT, ...)';
if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
extern void error (int __status, int __errnum, const char *__format, ...)
No such file or directory
是错误编号 ENOENT
并且在以下情况下被 execvp()
和朋友“returned”:
ENOENT The file pathname or a script or ELF interpreter does not exist.
(“ELF解释器”是动态链接器的同义词I guess)
chroot
实际上不知道 真正 出了什么问题,它只能报告 execvp()
在 errno
中输入的内容,我认为这就是错误含糊不清且有点误导的原因。
Why does chroot tell me the executable is missing when actually lib64/ld-linux-x86-64.so.2 is?
可执行文件本身不是 运行。
它类似于 shell 脚本 - 你有 #!/bin/sh
并且文件有可执行权限,所以你 ./file
它真的 运行s /bin/sh ./file
.
当您执行 ./file
并且文件是带有 PT_INTERP
的 ELF 文件时,来自 PT_INTERP
header 的文件被获取并且是 运行。所以真正发生的是,你真的 运行ning /lib64/ld-linux-x86-64.so.2 ./file
为(几乎)你系统上的每一个可能的可执行文件。您可以在您的系统上执行此操作 - /lib64/ld-linux-x86-64.so.2 /bin/bash
将 运行 Bash.
所以内核读取 /bin/bash
,看到它是一个 ELF 文件,读取 PT_INTERP
,然后 运行s /lib64/ld-linux-x86-64.so.2
。因为 /lib64/ld-linux-x86-64.so.2
不存在,内核将 errno
设置为 ENOENT
.
然后 chroot
程序检查 errno
,并打印消息 printf("Failed to run command <that command>: <error description>
。 chroot
不知道内核找不到程序解释器或可执行文件本身,它不知道。 chroot
只打印错误描述。