【问题标题】:Recover IP register after ilegal memory read or jump非法内存读取或跳转后恢复 IP 寄存器
【发布时间】:2016-08-20 02:11:43
【问题描述】:

指令指针寄存器如何从错误读取或错误跳转中恢复? 内核调用init 代码,该代码将调用main() 程序。如果main() 程序发生堆栈溢出或其他什么,并且RIP/EIP/IP 填充垃圾,操作系统如何恢复CPU 寄存器?

CPU只有一个指令指针对吗?因此,在我看来,从溢出中恢复似乎是不可能的。

【问题讨论】:

  • 单CPU不同的上下文。
  • 如果 CPU 执行的指令产生越界或非法读/写,则内存管理硬件将产生中断并将控制权转移到适当的预配置处理程序,而不管错误操作的地址或IP内容。

标签: c assembly x86 operating-system kernel


【解决方案1】:

如果 IP 加载了无法执行的地址,则会触发 EXCEPTION。 CPU 通常可以识别许多不同类型的异常,并用不同的编号来标识它们。

当异常发生时,它会导致 CPU 切换到内核模式。这反过来又会导致 CPU 使用定义为处理特定类型异常的处理程序的地址加载 IP,并加载内核模式堆栈。

有两种例外情况:故障和陷阱。发生故障后,可以重新启动IP中原来的指令。陷阱是致命错误。此时会发生什么取决于异常的类型。

如果是页面错误,处理程序将尝试将页面加载到内存中。

对于大多数其他异常,处理程序将尝试为特定类型的异常查找用户模式处理程序。见太监中的信号功能。

【讨论】:

    【解决方案2】:

    当您在用户模式中丢弃 IP 时,最终会发生硬件故障,可能是页面故障、非法操作码或类似的情况。然后处理器切换到主管/内核模式并通过将指令指针设置为明确定义的值来开始运行故障处理程序。

    然后内核代码将检查异常发生的地址和/或异常的类型。当发现这是因为其中任何一个原因时,内核通常会终止出现故障的用户模式进程。

    【讨论】:

    • 明白了。但是如何实现呢?我的意思是,我正在寻找一个可以保存进程状态的真实代码,找到下一个进程来恢复并将 IP 传递给该进程等等......这是否需要调度算法?像循环和先进先出?
    • Linux 0.01 有多任务? :o 不知道。谢谢。
    • @int3 实际上它确实没有从版本 0.01 中的这些错误中恢复,它只是停止了 ;)
    • 我正在阅读 include/linux/sched.h ,我从中了解到内核有一个带有进程 ID 的页面,以及一个用于所有寄存器和段的结构。创建任务时,它会将其保存在一个链接列表中,其中包含其最后状态的结构,对吗?类似的东西。
    • @int3 是的,那是正确的。现在,指向该结构的指针将存在于内核堆栈的“底部”,因此您可以通过将堆栈指针与堆栈的限制对齐来访问它,然后从那里访问任务结构。
    【解决方案3】:

    是的,如果 IP 被丢弃并导致故障,则只有错误值是已知的。目前尚不清楚“从溢出中恢复”是什么意思。当然,操作系统的故障处理程序有一个明确定义的地址,cpu 去那里,所以从那时起 IP 将被很好地定义。操作系统可能决定终止进程,或者如果程序安装了信号/异常处理程序,操作系统将确保调用它。然后,此处理程序可以使用适当的值加载 IP。

    【讨论】:

    • 嗯。因此,在使用适当的关键字进行一些研究后,我发现通过软件与硬件的“上下文切换”。我可以编写从硬编码的 2 个函数切换的 asm 代码,没有库,只是为了了解它在内部是如何工作的?
    猜你喜欢
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    相关资源
    最近更新 更多