登录进程初始化失败(wen7系统登陆进程初始化失败)

前段时间业务反映某型号服务器上bash更新后,ssh连接偶尔失败,客户端吐槽错误信息如下:这个版本bash是部门定制的,但是在实现上和原生版本没有区别。那么这些

前段时间业务反映某型号服务器上bash更新后,ssh连接偶尔失败,客户端吐槽错误信息如下:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图

这个版本bash是部门定制的,但是在实现上和原生版本没有区别。那么这些误差来自哪里呢?

更多linux内核视频教程文字资料可从后台私信【内核】免费获取。

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(1)

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(2)

以上各段(除代码段数据段外)的起始位置一般会根据系统是否启用random _ va _ space而略有变化,因此各段之间可能会有随机间隔。千言万语抵不上一张照片:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(3)

图1

所以现在的问题归结为:为什么目标进程的brk区域突然变得如此之小?首先检查bash的内存布局:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(4)

图2

这个进程的内存布局和一般的理解大相径庭,从低内存到高内存从上到下:
#1是进程的代码段和数据段。这两个区域一般在进程memories 空之间的最低点,但是现在明显有动态库映射在下部。

这不是我们想要的内存布局。我们想要的是成长为如下:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(5)

图3

看有没有不一样?两个bash进程都是64位的。不同的是,前者是sshd启动的进程,后者是我在终端上手动启动的。手动cat /proc/self/maps后,下64位cat的进程的内存布局正常:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(6)

图4

sshd流程呢?

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(7)

图5

sshd进程也不正常,无意中发现sshd是32位的,于是写了一个测试程序:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(8)

图6

下图中的数据段示例更复杂,因为它使用了指针。在这种情况下,指针gonzo(4字节内存地址)本身的值保存在数据段中。它指向的实际字符串不在这里。这个字符串存储在代码段中,代码段是只读的,保存所有的代码和零碎的东西,比如字符串值。该代码还将您的二进制文件映射到内存中,但是写入该区域将导致您的程序收到一个段错误。这有助于防止指针错误,虽然不如用C语言编程时注意预防有效。下图显示了我们示例中的这些段和变量:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(9)

您可以通过nm和objdump命令查看二进制映像并打印符号、它们的地址、段和其他信息。最后,需要指出的是,上面描述的虚拟地址布局在Linux中是一种“灵活的布局”,并且它已经作为默认布局使用了一些年。它假设我们有值RLIMIT_STACK。如果不是这样,Linux会恢复到“经典布局”,如下图所示:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(10)

虚拟地址之间的布局就到此为止空。下一篇文章将讨论内核如何跟踪这些内存区域。我们将分析内存映射,以了解文件的读写操作如何与它相关,以及内存使用配置文件的意义。

操作系统的锅吗?

现在,我们来看看内核有什么问题。目标系统版本如下。咨询系统组的人证实,该系统基于CentOS 6.5:http://vault.centos.org/6.5/centos plus/source/packages/kernel-2 . 6 . 32-431 . el6 . CentOS . plus . src

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(11)

图7

首先看一下函数arch/x86/mm/mmap . c:arch _ pick _ mmap _ layout()。其功能是根据过程和当前系统设置初始化mmap相关条目:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(12)

图8

mm-& gt;Get_unmapped_area是进程需要执行mmap时调用的最后一个函数。arch_get_unmap_area()用于以传统方式从低位搜索合适的位置。Arch_get_unmapped_area_topdown()以灵活布局的形式从高处寻找合适的位置,重点是125 ~ 129行。exec-shield引入了另一种专门针对32位进程的内存分配方法,规定如果要分配的内存需要可执行权限,那么应该从mm->: Shlib_base开始分配,在这里搜索合适的位置。shlib_base的值是SHLIB_BASE加上一个小的随机偏移量,而SHLIB_BASE的值是[7]:

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(13)

图9

下面的1641行显示了如何在mmap期间从mm结构中获取get_area函数。可以看到,只要MM->: Get _ unmarked _ exec _ area不是空,并且要分配的内存需要可执行权限,那么mm->: Get _ unmapped _ exec _ area就可以进行搜索。

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(14)

图10

其实上面的exec内存分配方法很容易造成冲突,redhat在这里做了很多补丁,如1、2、3所示。

问题并没有解决

上面的解释解释了为什么32位进程的内存布局异常,但这里的问题是,为什么当一个64位进程用32位进程启动时,64位进程也会受到影响。要想弄清楚这里的问题,我们得看看函数fs/bin fmt _ elf . c:load _ elf _ binary(),这个函数用于在当前进程中加载elf格式的可执行文件,然后跳转过来执行。该功能由32位elf和64位elf共享(借助一个相对隐藏的宏)。它的作用可以总结如下:
1 .
2、flush_old_exec():停止当前进程中的所有线程,清空空当前内存空,重置各种状态等。
3。设置新进程的状态,比如内存分配空、初始化等。
4。加载动态连接器并跳转执行它。

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(15)

图11

现在回到我们的问题,目前的进程是32位的,在64位系统上执行32位进程需要内核支持。当内核发现elf是32位程序时,它会在任务内部设置一个标志。通过调用上图中load_elf_binary()函数的第740行中的SET_PERSONALITY()来清除这个标志。所以在第721行,当前进程仍然认为它是32位的。flush_old_exec()做了什么?请参阅:fs/exec.c: flush_old_exec()

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(16)

图12

注意1039行,bprm->: Mm表示新的内存空室(旧的还在,新的马上就要发布了)。这里需要设置新的内存空房间。请参阅:fs/exec.c: exec_mmap()

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(17)

图13

我们可以看到,当当前进程还是32位时,内核初始化新内存空,导致arch_pick_mmap_layout()错误地将arch _ get _ unmapped _ exec _ area赋值给BPRM->;mm-& gt;Get_unmapped_exec_area是成员变量。虽然图-11中的load_elf_binary()函数在748行,32位标志清零空后调用set _ up _ new _ exec()-->:Arch_get_unmapped_exec_area(),但Arch _ get_unmapped_exec_area()不清零空mm-->变量get _ unmapped _ exec _ area导致execv后的进程为64位,但仍以mm开头-->:Shlib _ base作为起始地址进行搜索

解决方案

最直接可靠的方法就是输入arch_pick_mmap_layout(),用mm->: Get_unmapped_exec_area设置为NULL,但是需要修改内核。有以下几种方法可以避免用户模式:
1。将ulimit -s设置为unlimited,将exec-shield设置为0或1,然后重新启动该进程。这样,由于用户态的栈是无限的,内核只能以传统的方式给32位进程分配内存,不会陷入exec。
2。禁止randomize_va_space,但这种做法只是把头埋在沙子里。

总的来说,以上两种用户态规避方案,基本都是在哪里疼就在哪里贴一贴膏药,并不是解决问题的办法(而且有安全隐患)。换句话说,不要用32位进程启动64位进程是相对安全的。

登录进程初始化失败(wen7系统登陆进程初始化失败)插图(18)

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/114782.html

发表回复

登录后才能评论