我正在使用 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 +f
但set +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 。dash
http://raspbian.raspberrypi.org/raspbian stretch/main armhf
4.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 位值):