dash 不在 chroot 中扩展 glob 通配符

dash 不在 chroot 中扩展 glob 通配符

我正在使用 Raspbian 的副本,安装了皮根。 Pi-gen 在具有文件系统卷的 Docker 容器中运行,在卷debootstrap内运行自定义脚本。chroot

chroot我正在 Raspbian 文件系统内使用和运行 shell qemu-arm-static,但没有使用 Docker。

我注意到该mkinitramfs脚本不起作用。我将问题追溯到dash脚本运行的地方。

由于某种原因,dash未在命令中扩展文件名通配符:

# echo /*
/*
# ls /
bin boot dev etc home lib media mnt opt proc root run sbin sys tmp usr var

这种情况发生在 chroot 内的所有文件夹中,并且也在脚本中。这会破坏很多东西。

但是,通配符扩展在绑定安装在 内部的文件系统中正常工作chroot,例如/proc/run。此外,使用相同dash二进制文件的路径扩展可以在不同的chroot.

我已经尝试过set +fset +o noglob没有运气。该noglob选项肯定没有打开:

# set -o
Current option settings
errexit         off
noglob          off
ignoreeof       off
interactive     on
monitor         on
noexec          off
stdin           on
xtrace          off
verbose         off
vi              off
emacs           off
noclobber       off
allexport       off
notify          off
nounset         off
nolog           off
debug           off

我正在运行来自 的软件包0.5.8-2.4版本。主机运行带有 kernel 的 Kali Linux 2019.1 。dashhttp://raspbian.raspberrypi.org/raspbian stretch/main armhf4.19.0-kali4-amd64

以前有人见过类似的问题吗?我可以使用什么作为解决方法?

更新:以下是strace工作中转储的相关部分chroot

read(0, "echo /*\n", 8192)              = 8
openat(AT_FDCWD, "/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents(3, /* 11 entries */, 32768)    = 264
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
write(1, "/bin /dev /etc /lib /pls /proc /"..., 46) = 46

在非工作状态下也是如此chroot

read(0, "echo /*\n", 8192)              = 8
openat(AT_FDCWD, "/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents64(3, /* 20 entries */, 32768)  = 488
close(3)                                = 0
write(1, "/*\n", 3)                     = 3

答案1

原因

作为艾蒂安发现了(请为他们的研究工作投票),根本原因似乎是 glibc 2.28 的变化。

  • getdents64在 64 位 Linux 上可以返回d_off不适合 32 位int.在 32 位系统上,它仅返回 32 位值。
  • qemu-user在 64 位 Linux 上模拟 32 位系统只是传递系统调用,因此 32 位用户态进程可以获得溢出的值。
  • glibc 2.28 有一个改变这使得readdir总是使用并在不适合getdents64时出错。d_off在真正的 32 位系统上,这一定不会引起问题,因为 glibc 会处理它。 (以前它getdents在 32 位系统上调用,这会返回 32 位值并且内核会进行任何截断。)

修复(或缺少修复)

这个 glibc 错误目前正在跟踪此问题的进展。修复并最终部署到您的发行版需要时间。

解决方法

  • 我能看到的最简单的解决方法是在具有 32 位 Linux 内核的系统上运行这些构建。
  • 如果您可以将 glibc 版本(在 chroot 中!)降级到 2.27,这将解决该问题,但这可能会导致依赖性问题并会改变您正在构建的映像。
  • 人们还可以在链接线程中应用众多补丁之一,但这需要编译(并且可能从包管理器中分离)您的内核、glibc 或(可能是最简单的)QEMU。

答案2

我的机器上有完全相同的症状,即使我正在开发一个不同的项目(基于 docker,而不是 QEMU),所以我无法证明这是你的情况的问题,但它可能是。

我有一个有时工作,有时失败的构建,因为通配符并不总是得到扩展(我正在做ls /tmp/linux*deb)。

Strace 显示,对于失败的情况,将返回对 getdents 的调用-1 EOVERFLOW (Value too large for defined data type)

工作案例:

[pid 29791] open("/tmp", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
[pid 29791] fstat64(3, {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0
[pid 29791] getdents(3, /* 3 entries */, 32768) = 60
[pid 29791] getdents(3, /* 0 entries */, 32768) = 0
[pid 29791] close(3)                    = 0

失败案例:

[pid 25606] open("/tmp", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
[pid 25606] fstat64(3, {st_mode=S_IFDIR|S_ISVTX|0777, st_size=100, ...}) = 0
[pid 25606] getdents(3, /* 1 entries */, 32768) = 16
[pid 25606] getdents(3, 0x585a831c, 32768) = -1 EOVERFLOW (Value too large for defined data type)
[pid 25606] close(3)                    = 0

我发现了几个引用该问题的错误报告(getdents 返回 64 位值,但在这种情况下调用者期望 32 位值):

相关内容