在 Ubuntu 20.04 上运行旧的 32 位应用程序

在 Ubuntu 20.04 上运行旧的 32 位应用程序

我们目前有一个必须运行的古老(1995 年)32 位应用程序,名为 Muscat。(没有源代码 - 这是一个商业应用程序。)

它可以运行在 Ubuntu 18.04 上,但我还不能让它在 20.04 上运行。因此,我们一直在运行 18.04 VM,但很快就会停止支持,我希望能够正确地做到这一点。由于数据量巨大,我们目前只能使用这个系统,但迁移需要大量的整理工作,而我们的资金有限。

我知道 i386 的变化宣布,但 Linux 的整个领域对我来说相当陌生。

该应用程序可执行文件名为fx.sp

我们将其作为包装脚本运行,其中包含:

/lib/ld-linux.so.2 ./fx.sp

在 20.04 上运行该程序可得到:

/lib/ld-linux.so.2 fx.sp
Segmentation fault (core dumped)

我真的不知道该如何继续,不过我在这里的假设是,鉴于它以前确实起作用,要么是库不存在,要么是函数调用指向了现在缺失的某个 32 位子系统。

我发现 ldd 用于查看依赖关系,结果如下:

ldd /lib/ld-linux.so.2 fx.sp
/lib/ld-linux.so.2:
    statically linked
fx.sp:
    linux-gate.so.1 (0xf7f6f000)
    libdl.so.1 => /lib/libdl.so.1 (0xf7f4c000)
    libc.so.5 => /lib/libc.so.5 (0xf7e83000)

上述三个库都存在,并且符号链接到我们每年在机器升级时保留的原始库文件的中央副本:

ls -lAF /lib/ld-linux.so.2 /lib/libdl.so.1 /lib/libc.so.5
lrwxrwxrwx 1 root root 25 Apr  7  2022 /lib/ld-linux.so.2 -> i386-linux-gnu/ld-2.31.so*
lrwxrwxrwx 1 root root 50 Jan 27  2015 /lib/libc.so.5 -> /software/muscat/libraries/libc.so.5.3.12
lrwxrwxrwx 1 root root 51 Jan 27  2015 /lib/libdl.so.1 -> /software/muscat/libraries/libdl.so.1.7.14

我知道 linux-gate.so.1 是内核中的虚拟表示,因此不存在。

我们也安装了 i386 架构,如下所示:

dpkg --add-architecture i386
sudo apt-get update
sudo apt-get -y install libc6:i386 

我创建了一个核心转储,它提供:

gdb fx.sp /var/lib/apport/coredump/core...
...
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0xf7f3c686 in __libc_init () from /lib/libc.so.5

/lib/libc.so.5文件是我们保存了20年的原始图书馆之一。

运行没有包装器的 strace 后,我得到:

工作 18.04机器:

$ strace -o strace.webmuscat1804 /lib/ld-linux.so.2 ./fx.sp
execve("/lib/ld-linux.so.2", ["/lib/ld-linux.so.2", "./fx.sp"], 0x7ffe3d4d3ef8 /* 25 vars */) = 0
brk(NULL)                               = 0x56bdb000
openat(AT_FDCWD, "./fx.sp", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0\3\0\1\0\0\0\0\224\4\0104\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0775, st_size=1431032, ...}) = 0
getcwd("/path/to/cgi-bin-private", 128) = 59
mmap2(0x8048000, 811008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x8048000
mmap2(0x810e000, 483328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xc5000) = 0x810e000
mmap2(0x8184000, 210672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x8184000
mprotect(0xffe59000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|PROT_GROWSDOWN) = 0
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f7f000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=64923, ...}) = 0
mmap2(NULL, 64923, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7f3e000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libdl.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@\7\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=6875, ...}) = 0
mmap2(NULL, 8504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7f36000
mmap2(0xf7f38000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0xf7f38000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libc.so.5", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0(k\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=699832, ...}) = 0
mmap2(NULL, 820372, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7e66000
mmap2(0xf7ef7000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x90000) = 0xf7ef7000
mmap2(0xf7efd000, 201876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf7efd000
close(3)                                = 0
set_thread_area({entry_number=-1, base_addr=0xf7f7ff40, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
munmap(0xf7f3e000, 64923)               = 0
personality(PER_LINUX)                  = 0 (PER_LINUX)
geteuid()                               = 1001
getuid()                                = 1001
getgid()                                = 1001
getegid()                               = 1001
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f7e000
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(1, "FX 1.4 24/02/1998 (Actually comp"..., 59) = 59
write(1, "Options: LOGGING UNIX COMPILED ("..., 42) = 42
write(1, "Enter NAME=VALUE lines, end with"..., 44) = 44
write(1, "Content-type: text/html\n\n", 25) = 25
brk(NULL)                               = 0x56bdb000
brk(0x56bdb068)                         = 0x56bdb068
brk(0x56bdc000)                         = 0x56bdc000
open("/etc/muscat-fx.cf", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=35, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f50000
read(3, "/usr/local/MuscatFX/src/muscat 8"..., 4096) = 35
lseek(3, -1, SEEK_CUR)                  = 34
close(3)                                = 0
munmap(0xf7f50000, 4096)                = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f50000
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
read(0, 0xf7f50000, 1024)               = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++

以及不工作 20.04机器:

execve("/lib/ld-linux.so.2", ["/lib/ld-linux.so.2", "./fx.sp"], 0x7ffce2848dc8 /* 26 vars */) = 0
brk(NULL)                               = 0x58335000
arch_prctl(0x3001 /* ARCH_??? */, 0xff8f1038) = -1 EINVAL (Invalid argument)
openat(AT_FDCWD, "./fx.sp", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0\3\0\1\0\0\0\0\224\4\0104\0\0\0"..., 512) = 512*emphasized text*
getcwd("/path/to/cgi-bin-private", 128) = 45
mmap2(0x8048000, 811008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x8048000
mmap2(0x810e000, 483328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xc5000) = 0x810e000
mmap2(0x8184000, 210672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x8184000
mprotect(0xff8f1000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|PROT_GROWSDOWN) = 0
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7ef2000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=107716, ...}) = 0
mmap2(NULL, 107716, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7ed7000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libdl.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@\7\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=6875, ...}) = 0
mmap2(NULL, 8504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7ed4000
mmap2(0xf7ed6000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0xf7ed6000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libc.so.5", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0(k\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=699832, ...}) = 0
mmap2(NULL, 820372, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7e0b000
mmap2(0xf7e9c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x90000) = 0xf7e9c000
mmap2(0xf7ea2000, 201876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf7ea2000
close(3)                                = 0
set_thread_area({entry_number=-1, base_addr=0xf7ef2fc0, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
munmap(0xf7ed7000, 107716)              = 0
personality(PER_LINUX)                  = 0 (PER_LINUX)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x95da8} ---
+++ killed by SIGSEGV (core dumped) +++

这就是我所知道的。

PS 最终,我想将设置容器化,如果有人能对此提供一些好的建议,那也会很有帮助。

答案1

最后,我使用带有 18.04 镜像的 Docker 将应用程序容器化。

答案2

为了避免长篇大论,我把所有评论都放在了这个答案框里。稍后我会把它们全部整合起来。

我已经研究过这两个strace输出并有一些快速的观察。

(7)在工作情况和非工作情况中,我们都使用 /path/to/wrapper.fx.sp ,但内容似乎不同?

工作案例:

openat(AT_FDCWD, "/path/to/wrapper.fx.sp", O_RDONLY) = 3  
read(3, "#!/bin/bash\n/lib/ld-linux.so.2 /"..., 80) = 80  

脚本的开头如下:

#!/bin/bash  
/lib/ld-linux.so.2 /  

非工作情况:

openat(AT_FDCWD, "/path/to/wrapper.fx.sp", O_RDONLY) = 3  
read(3, "#!/bin/bash\n\n#ulimit -S -c unlim"..., 80) = 80  

脚本现在开始如下:

#!/bin/bash  
#ulimit -S -c unlim  

(8) 此外,这只是一个“包装器”shell 脚本。我们可能需要查看它以检查它最终将运行什么二进制文件(例如 /bin/MUSCAT),然后执行ldd /bin/MUSCAT以收集更多调试点,例如了解缺少什么或哪个库版本不匹配。

(9)在工作案例中,我们有 UserID 1001,它使用目录“/home/myusername”:

getuid()                                = 1001  
"/home/myusername"  

然而,在工作案例中,我们有用户 ID 501 并且目录“/home/myusername”未被使用(它使用默认当前目录):

getuid()                                = 501  
"/path/to..."  

我们是否可以检查是否可以在非工作情况下使用相同的用户和相同的目录(可能使用相同的配置,如 ~/.muscat.conf )?
目的是消除二进制文件中的一些硬编码路径。

我们正在尝试调试该问题。
我们最终可能会找出导致其崩溃的配置中的确切更改。我们是否可以修复是另一个问题!

最新更新:

检查strace /lib/ld-linux.so.2 ./fx.sp

在这里,工作案例mmap2()在“820372+24576+201876 字节”上执行
,然后munmap()“64923 字节”
& 然后personality(PER_LINUX)
& 然后转到 UID 函数geteuid()&getuid()

而非工作案例mmap2()在“820372+24576+201876 字节”(相同)上执行
,然后munmap“107716 字节”(更多!!!!)
然后最后执行personality(PER_LINUX)
并且没有进入 UID 函数。

结论:

(不太可能 1)也许 Ubuntu 20.04 不再支持 PER_LINUX,并且需要 PER_LINUX32
https://man7.org/linux/man-pages/man2/personality.2.html

(更有可能的是 2)有一个代码错误,webmuscat其中错误地取消了更多内存的映射,然后访问未映射的内存,这将生成 SIGSEGV!
https://linux.die.net/man/2/mmap2&https://linux.die.net/man/2/munmap
以下是关键部分:

The munmap() system call deletes the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references

subsequent references to these pages will generate SIGSEGV

在这种情况下,我们必须研究 C 源代码来修复以奇怪的方式触发的 Bug。

相关内容