首先通过
创建一个匿名内存块int fd = memfd_create("", MFD_CLOEXEC);
请注意,我传递了MFD_CLOEXEC标志。 然后,我将elf文件的内容复制到该匿名内存中。 小精灵是这样执行的:
char cmd[128];
sprintf(cmd, "/proc/self/fd/%i", fd);
execl(cmd, "dummy", NULL);
MFD_CLOEXEC意味着fd将在execl之后关闭,但是execl需要从fd加载elf内容。我做了一个简单的测试,看来还可以。但是我不确定它是否安全。
更新:
#define _GNU_SOURCE
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdio.h>
extern uint8_t foo_data[] asm("_binary_htop_start");
extern uint8_t foo_data_size[] asm("_binary_htop_size");
extern uint8_t foo_data_end[] asm("_binary_htop_end");
int main(int argc, char **argv)
{
int exefd = memfd_create("", MFD_CLOEXEC);
printf("%p %d %ld\n", foo_data, exefd, write(exefd, foo_data, foo_data_end-foo_data));
char * const vv[] = {"htopp", NULL};
//execveat(exefd, NULL, vv, NULL, AT_EMPTY_PATH);
exefd = syscall(__NR_execveat, exefd, NULL, vv, NULL, AT_EMPTY_PATH);
perror("");
return 0;
}
我尝试使用execveat但失败了。 syscall将errno设置为“错误地址”,不知道原因。 elf内容由objcopy生成。
答案 0 :(得分:0)
对于真正的二进制文件(如ELF文件),无论是静态链接还是动态链接,它都很好。
MFD_CLOEXEC
不适用于可执行脚本(例如,以#! /bin/sh
开头的文件)。在这种情况下,您必须忽略该标志并使fd保持打开状态。
您应该研究使用sprintf
(而不是execl
/ execveat(fd, "", argv, env, AT_EMPTY_PATH)
的把戏)(不幸的是,使用O_CLOEXEC
打开的可执行脚本也有同样的问题,但事实并非如此) t依赖于/proc
fs的安装)。
当然,对于变量函数,例如(void*)0
,应该始终使用NULL
而不是execl()
;-)