LD_PRELOAD-执行go可执行文件时未调用共享库中的构造方法

时间:2020-05-19 07:33:19

标签: c go alpine ld-preload

在Alpine映像中内置的GO可执行文件周围有一个奇怪的行为,其中标准的LD_PRELOAD功能无法正常工作。

动态加载程序似乎没有调用构造函数

我有一个示例go应用程序(getgoogle.go):

package main

import (
    "fmt"
    "net/http"
)

func main() {
    resp, err := http.Get("http://google.com/")
    if err == nil {
        fmt.Println(resp.StatusCode)
    }
}

示例共享对象代码(libldptest.c

#include <stdio.h>

static void __attribute__((constructor)) StaticConstructor(int argc, char **argv, char **env)
{
    printf(">>> LD_PRELOADED!\n");
}

我正在使用此Dockerfile(gotest映像)创建基于debian的Docker映像:

FROM golang
COPY libldptest.c hello-world.go /
RUN gcc -shared -o /libldptest.so /libldptest.c
RUN go build -gcflags='-N -l' -o /getgoogle /getgoogle.go
ENV LD_PRELOAD=/libldptest.so

然后运行以下命令:

$docker run -it gotest /getgoogle
>>> LD_PRELOADED!
200

这意味着构造函数在这里起作用。

但是当对基于高山的docker映像进行相同操作

FROM golang:1.12-alpine
RUN apk add gcc libc-dev
COPY libldptest.c hello-world.go /
RUN gcc -shared -o /libldptest.so /libldptest.c
RUN go build -gcflags='-N -l' -o /getgoogle /getgoogle.go
ENV LD_PRELOAD=/libldptest.so

并运行与上述相同的命令

$docker run -it gotest /getgoogle
200
$docker run -it gotest ls
>>> LD_PRELOADED!
bin  src

运行go应用程序时未调用静态构造函数! (但是在运行ls时被调用)

请注意,我已经检查了动态加载程序是否将该库添加到了进程空间。

很高兴了解为什么它不起作用。

2 个答案:

答案 0 :(得分:0)

停止忽略第一条评论。如果您坚持使用Go的内部链接器,而内部链接器的链接方式与libc使用兼容,那么您就不能使用任何C代码,包括LD_PRELOAD ed C代码甚至动态链接器本身的功能。正如Florian(来自glibc)在链接问题中所说的那样,它对glibc也不有效,并且只能在此偶然地“起作用”。

即使您以某种方式“机械”地找出未调用ctor的原因,您仍在处于损坏的进程状态下运行C代码,并且可能会出错。即使您分析了所有内容,而且看起来还不错,但是在下一次动态链接程序/ libc更新中,情况可能会完全改变。

如果要执行此操作,请在Go中使用外部链接器选项。

答案 1 :(得分:0)

从注释中可以看出,Go / Alpine环境中的静态构造函数存在一个主要问题。简而言之,从ABI的角度来看,调用静态构造函数的要求被分配给可执行文件,而不是加载程序。 Go可执行文件不是基于C运行时的,它仅调用依赖项共享对象的静态构造函数,而不调用LD_PRELOAD版本的共享对象。在使用glibc的情况下,LD_PRELOAD版的共享对象的构造函数由实现而非加载程序设计调​​用。在musl-libc上不是。

我做了一个“ hack” -ish 解决方法,以使现有的Go应用可与LD_PRELOAD版的共享对象一起使用。我使用的事实是,在musl-libc的环境中该库是LD_PRELOAD-ed正确的,而Go在 初始化的早期阶段。

我在pthread_create-ed共享对象中重写/钩住了pthread_create符号,并使用它来调用构造函数。

LD_PRELOAD

注意事项:可以在当前的Go运行时中使用,但此解决方案的假设远未成为未来的证明。 Next Go版本可以轻松破解它。

相关问题