在另一个进程内从内存中执行一个进程?

9
我希望有一个小的“应用程序加载器”程序,可以通过TCP从外部服务器接收其他二进制应用程序文件并运行它们。
我可以将传输的文件保存到硬盘上,并使用system()调用来运行它。但是,我想知道是否可能从内存中启动新应用程序,而不必触及硬盘。
在加载新应用程序后,加载程序的状态无关紧要。我更喜欢使用C语言,但如果有C++解决方案也可以。如果可能的话,我也希望坚持使用标准Linux C函数,不使用任何外部库。

2
你可以将它写入内存磁盘上的文件。 - TJD
1
我也倾向于认为,在一个相当新的CPU上,任何级别的操作系统安全性都会尽其所能确保这种情况不会发生。虽然这是可行的,但在现实世界的发行版上使用起来会非常麻烦(我希望如此)。 - BRPocock
话虽如此,你可能需要看看glibcld-linux实际上是做什么的,因为这就是它为普通的磁盘可执行文件所做的事情。这并不美观... - BRPocock
@BRPocock: 其实这种做法很常见(http://en.wikipedia.org/wiki/Executable_compression)。 - Yakov Galka
@GigaWatt:再读一遍问题:“在加载新应用程序后,加载程序的状态不重要。”所以这实际上是OP想要的。因此,他可以查看我链接的页面上的一些开源打包程序。 - Yakov Galka
显示剩余4条评论
3个回答

6

简短回答:不行。

长话短说:在不写入磁盘的情况下实现这一点可能会非常棘手。你可以理论上编写自己的 ELF 加载器来读取二进制文件,映射一些内存,处理必须的动态链接,然后转移控制权,但是这需要大量工作,很少有人愿意付出这样的努力。

接下来最好的解决方案是将其写入磁盘并尽快调用 unlink。磁盘甚至不必是“真正”的磁盘,它可以是 tmpfs 或类似的东西。

我最近使用的另一个选择是不传递完整的已编译二进制文件,而是传递 LLVM 字节码,然后根据需要进行 JIT/解释/保存。这也具有在异构环境中使您的应用程序工作的优点。

尝试使用 fmemopenfilenofexecve 的组合可能很诱人,但由于以下两个原因,这种方法不起作用:

  1. 来自 fexecve() 页的说明:

    “文件描述符 fd 必须以只读方式打开,并且调用者必须有执行 它指的文件 的权限”

    即它需要是一个指向文件的 fd。

  2. 来自 fmemopen() 页的说明:

    “返回这些函数的文件流未关联文件描述符(即,如果在返回的流上调用 fileno(3),将返回错误)”


谢谢您的回复,这正是我所需要的。在谷歌上搜索这个主题并没有帮助我很多,我需要满足我的好奇心! - Flip
请注意,现在的标准是在/dev/shm/挂载一个tmpfs - caf
现在可以使用memfd_create()和fexecve()来运行内存中的可执行文件。请参见https://unix.stackexchange.com/questions/230472/can-i-exec-an-entirely-new-process-without-an-executable-file - ArtemB

0

比在C语言中实现更容易的方法是设置一个tmpfs文件系统。您将拥有硬盘接口的所有优势,从您的程序/服务器/任何地方,您只需执行exec即可。这些类型的虚拟文件系统现在非常高效,页面缓存中实际上只有一个可执行文件的副本。

正如Andy所指出的那样,为了使这种方案有效,您必须确保不使用缓冲写入文件,而是直接在原地“写入”(广义上)。

  • 您必须知道可执行文件的大小
  • 在tmpfs上创建一个文件
  • 使用ftruncate将其缩放到该大小
  • 使用mmap将该文件“映射”到内存中,以获取缓冲区的地址
  • 将该地址直接传递给recv调用,以在原地写入数据
  • munmap文件
  • 使用该文件调用exec
  • rm文件。即使可执行文件仍在运行,也可以完成此操作

说实话,如果你的存储已经满了,tmpfs 不会比本地文件系统更快。写入会被缓冲到内存中,以便立即执行 execve() 时可以从缓存中映射它们。你所付出的唯一代价是最终刷新到磁盘上,这是异步的。 - Andy Ross
@AndyRoss,不要为这样的事情使用缓冲写入,我会更新我的答案。 - Jens Gustedt
1
即使这只是避免了一次内存复制。这里的性能限制是什么?我很难想象一个情况,文件系统中写入速度是限制因素,但网络接收数据包的速度却不是。看起来过于复杂了。只需打开/写入您的常规文件系统,省去麻烦。 - Andy Ross

0

你可能想要查看并重复使用UPX,它将可执行文件解压缩到内存中,然后将控制权转移到ld-linux以启动它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接