当前位置: 首页 > 知识库问答 >
问题:

为什么不鼓励静态链接glibc?

陈斌
2023-03-14

大多数在线来源都表明您可以静态链接glibc,但不鼓励这样做;例如centos包repo:

glibc静态包包含用于静态链接的C库静态库。你不需要这些,除非你静态链接,这是非常不鼓励的。

这些消息来源很少(或从未)说明为什么这是个坏主意。

共有3个答案

刘野
2023-03-14

我能想到一个允许静态链接的好理由。如果有人获得了系统的访问权,他们可以用一个包含恶意软件的文件替换libc.so。当您的应用程序运行时,它将执行恶意软件。如果应用程序是用静态glibc构建的,那么攻击媒介就会消失。

益阳平
2023-03-14

程序/glibc接口由POSIX、C和C标准以及其他标准标准化和文档化。例如,fopen()函数的行为符合C标准,而pthread_mutex_lock()的行为符合POSIX标准。

glibc/内核接口未标准化。fopen() 在引擎盖下使用 open() 吗?还是它使用openat()?还是别的什么?明年它将使用什么?你不知道。

如果<code>glibc/内核接口发生更改,则使用任何更改但静态链接<code>glibc</code>的程序将不再工作。

15年前,正是因为这个原因,Solaris删除了< code>libc的所有静态版本。

静态链接-它去哪里了?

使用 Solaris 10,您无法再构建静态可执行文件。这并不是说 ld(1) 不允许静态链接,或者使用存档,只是 libc.a,libc.so.1 的存档版本,不再提供。这个库提供了用户土地和内核之间的接口,如果没有这个库,很难创建任何形式的应用程序。

我们警告用户不要使用静态链接已经有一段时间了,针对libc.a的链接尤其成问题。每一个solaris发行版或更新(甚至一些补丁)都会导致一些针对libc.a构建的应用程序失败。问题是,libc应该将应用程序与用户/内核边界隔离开来,这个边界在不同的版本之间会发生变化。

如果应用程序是针对 libc.a 构建的,那么它引用的任何内核接口都会从归档文件中提取出来,并成为应用程序的一部分。因此,此应用程序只能在与使用的内核接口同步的内核上运行。如果这些接口发生更改,应用程序将踩在摇摇欲坠的地面上。

...

编辑:

似乎严重高估了Linux内核接口的稳定性。有关详细信息,请参阅Linux内核API更改/添加。总结:

易英奕
2023-03-14

其他回答中给出的理由是正确的,但不是最重要的理由。

glibc不应该静态链接的最重要原因是它在内部广泛使用dlopen来加载NSS(Name Service Switch)模块和icon v转换。模块本身引用C库函数。如果主程序与C库动态链接,那没问题。但是如果主程序与C库静态链接,dlopen必须加载C库的第二个副本以满足模块的加载要求。

这意味着您的“静态链接”程序仍然需要文件系统上存在libc.so.6的副本,加上NSS或iconv或任何模块本身,以及模块可能需要的其他动态库,如ld-linux.so.2libresolv.so.2等。这不是人们在静态链接程序时通常想要的。

这也意味着静态链接的程序在其地址空间中有两个C库的副本,它们可能会争夺使用哪个<code>标准输出</code>缓冲区,谁可以用非零参数调用<code>sbrk</code>等等。在glibc中有一堆防御逻辑试图使其工作,但它从未保证工作。

您可能认为您的程序不需要担心这一点,因为它从不调用<code>getaddrinfo,但语言环境支持在内部使用<code>iconv函数可能会触发对<code>dlopen

例如,如果您的程序确实调用了iconv,那么情况会变得更糟,特别是当“静态链接”的可执行文件构建在一个发行版上,然后复制到另一个发行版时。iconv 模块有时位于不同发行版的不同位置,因此在红帽发行版上构建的可执行文件可能无法在 Debian 发行版上正常运行,这与人们希望从静态链接的可执行文件中获得的完全相反。

 类似资料:
  • 问题内容: 这是来自Hibernate的官方教程: 还有一个替代声明,该声明允许使用组合键访问旧数据。强烈建议不要将其用于其他任何用途。 为什么不鼓励使用复合键?我正在考虑使用一个三列表,其中所有列都是外键,并且一起形成一个主键,这在我的模型中是有意义的关系。我不明白为什么这是一个坏主意,特别是我将在它们上使用索引。 有什么选择?创建一个额外的自动生成的列并将其用作主键?无论如何,我仍然需要查询我

  • Django Rest框架序列化程序不调用。给出的解释是,这导致了Django Rest Framework 3.0发行说明中的“更清晰的关注点分离”: 此更改还意味着我们不再使用方法,但在序列化程序上显式执行所有验证。这提供了更清晰的分离,并确保ModelSerializer类上没有自动验证行为,而这些行为也不能轻松地复制到常规序列化程序类上。 但是DjangoRest框架的作者试图分离哪些问题

  • 问题内容: Model.clean验证模型序列化器时,Django Rest Framework序列化器不会调用。给出的解释是,这导致了Django Rest Framework 3.0发行说明中的 “更清晰的关注点分离” : ModelSerializer验证和ModelForm之间的差异。 此更改还意味着我们不再.full_clean()在模型实例上使用该方法,而是在序列化程序上显式执行所有验

  • 问题内容: 关于Java EE开发的第一件事是,我不应该在Java EE容器中生成自己的线程。但是当我考虑它时,我不知道原因。 您能清楚地解释为什么不鼓励这样做吗? 我确信大多数企业应用程序都需要某种异步作业,例如邮件守护程序,空闲会话,清理作业等。 因此,如果确实不应该产生线程,那么在需要时正确的方法是什么? 问题答案: 不建议这样做,因为环境中的所有资源都应由服务器进行管理,并可能由服务器进行

  • 问题内容: 为什么我的内部类中没有接口?为什么是天生的?抱歉,如果这是一个愚蠢的问题,我已经尽力一遍又一遍地用Google搜索,但似乎无法将其包裹在脑海中。如为什么不能在内部类/局部类中声明这些? 同样作为一个确认,我们在接口中可以包含静态最终变量的原因是因为它们未指定状态或任何此类实现权?如果我们输了而只使用了final,那么我们需要一个没有意义的实例,因为您无法实例化接口。抱歉,我真的很困惑,