Linux上执行内存中的脚本和步伐

打印 上一主题 下一主题

主题 547|帖子 547|积分 1641

在Linux中可以不需要有脚本或者二进制步伐的文件在文件体系上实际存在,只需要有对应的数据在内存中,就有办法执行这些脚本和步伐。
原理其实很简单,Linux里有办法把某块内存映射成文件形貌符,对于每一个文件形貌符,Linux会在/proc/self/fd/这个路径上创建一个对应形貌符的实体,这个路径可以当成普通的文件来用,能正常从中读出数据,因此只要有可执行权限,就可以加载后运行。
其中第一步是创建内存到文件形貌符的映射,这一步可以靠memfd_create这个体系调用实现。这个体系调用会返回一个文件形貌符,关联到一块内存上,默认大小是0,大多数对普通文件形貌符可行的操作对这个形貌符也都可用,好比read,write,ftruncate,close。write数据进去的时间体系会自动分共同适长度的内存。当所有引用这块内存的fd被close之后,这块内存会被自动释放。
总之memfd_create提供了像操作文件一样操作内存的能力,是统统皆文件理念的体现之一。
而且memfd_create创建的页面默认有可执行权限,在proc底下的对应的形貌符文件也有可执行权限。
所以我们只要把脚本或者二进制步伐的数据写进memfd_create返回的形貌符就已经做完前两步了。其中对于脚本有一些要求,需要带有Shebang(雷同#!/usr/bin/env python3这种)。
有一点需要注意,固然/proc/self/fd/有形貌符文件存在,但实际上这就是个软链接,而我们的数据全在内存里。
写入成功后可以使用execve执行proc下的形貌符文件,也可以通过fexecve体系调用直接调用文件形貌符。golang没提供fexecve,所以示例用exec.Cmd。
例子:
  1. package main
  2. import (
  3.         "fmt"
  4.         "os"
  5.         "os/exec"
  6.         "golang.org/x/sys/unix"
  7. )
  8. func main() {
  9.     // 名字其实无所谓,传空字符传也许,名字只是方便debug没有其他影响
  10.         fd, err := unix.MemfdCreate("memexec", unix.MFD_CLOEXEC)
  11.         if err != nil {
  12.                 panic(err)
  13.         }
  14.         file := os.NewFile(uintptr(fd), "memexec")
  15.         defer func() {
  16.                 if err := file.Close(); err != nil {
  17.                         panic(err)
  18.                 }
  19.         }()
  20.         _, err = file.Write([]byte("#!/usr/bin/env python\nimport math\nprint('Hello, world!')\n"))
  21.         if err != nil {
  22.                 panic(err)
  23.         }
  24.         _, err = file.Write([]byte("print(f'{math.sqrt(2)=}')\n"))
  25.         if err != nil {
  26.                 panic(err)
  27.         }
  28.     // 因为设置了CLOEXEC,子进程里execve之后看不到这个描述符,会导致调用失败
  29.     // 所以只能用父进程的
  30.         cmd := exec.Command(fmt.Sprintf("/proc/%d/fd/%d", os.Getpid(), fd))
  31.         data, err := cmd.Output()
  32.         fmt.Println("output:", string(data))
  33.         if err != nil {
  34.                 panic(err)
  35.         }
  36. }
复制代码
golang的话还以共同embed把二进制步伐的数据提前嵌入步伐内,如许写入的时间会比力方便。
安全性:memfd_create创建的东西默认有可执行权限,同时默认也是可写的,很可能会被恶意步伐使用,所以目前内核也在推进解决这个问题已经添加了flag可以让不添加可执行权限,这里建议是遵守权限最小化的原则。
memfd本来的用途:用来在内存中创建文件(好比不想在存储器上创建文件时可以用这个),并可以在父子进程间传递(最好共同file sealing api使用,防止数据被意外修改);或者干脆当匿名共享内存用。执行内存中的步伐是附带效果。
参考资料

https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

万有斥力

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表