首页 > 系统相关 >Linux 内核黑客不可靠指南【ChatGPT】

Linux 内核黑客不可靠指南【ChatGPT】

时间:2023-12-09 11:22:23浏览次数:49  
标签:上下文 中断 linux 调用 黑客 内核 Linux ChatGPT include

Rusty Russell's "Unreliable Guide to Hacking the Linux Kernel"

作者

Rusty Russell

简介

欢迎阅读 Rusty's Remarkably Unreliable Guide to Linux Kernel Hacking。本文档描述了内核代码的常见例程和一般要求:其目标是为有经验的 C 程序员提供 Linux 内核开发的入门指南。我避免了实现细节:这就是代码的用途,我忽略了一些有用的例程。

在阅读本文之前,请了解我从未想过要写这个文档,因为我明显不够资格,但我一直想阅读它,这是唯一的方法。我希望它会成为最佳实践、常见起点和随机信息的汇编。

主要内容

参与者

在系统中,每个 CPU 都可能处于以下状态之一:

  • 未与任何进程关联,为硬件中断提供服务;
  • 未与任何进程关联,为软中断或任务队列提供服务;
  • 在内核空间运行,与进程关联(用户上下文);
  • 在用户空间运行进程。

这些之间存在一种顺序。底部两个可以相互抢占,但在它们之上是严格的层次结构:每个只能被其上方的部分抢占。例如,当一个软中断在 CPU 上运行时,没有其他软中断会抢占它,但硬件中断可以。然而,系统中的任何其他 CPU 都是独立执行的。

我们将看到用户上下文如何阻塞中断,以成为真正的不可抢占状态。

用户上下文

用户上下文是指从系统调用或其他陷阱进入时的状态:与用户空间一样,您可能会被更重要的任务和中断抢占。您可以通过调用 schedule() 进行休眠。

注意

在模块加载和卸载以及块设备层的操作中,您始终处于用户上下文中。

在用户上下文中,当前指针(指示当前执行的任务)是有效的,并且 in_interrupt()(include/linux/preempt.h)为 false。

警告

请注意,如果禁用了抢占或软中断(见下文),in_interrupt() 将返回错误的结果。

硬件中断(硬中断)

定时器滴答声、网络卡和键盘是实际硬件的例子,它们可以在任何时候产生中断。内核运行中断处理程序,为硬件提供服务。内核保证此处理程序永远不会重新进入:如果相同的中断到达,它将被排队(或丢弃)。由于它禁用了中断,因此此处理程序必须快速:通常它只是确认中断,标记要执行的“软中断”,然后退出。

您可以通过 in_hardirq() 返回 true 来判断是否在硬件中断中。

警告

请注意,如果禁用了中断(见下文),这将返回错误的结果。

软中断上下文:软中断和任务队列

每当系统调用即将返回到用户空间,或者硬件中断处理程序退出时,任何标记为挂起的“软中断”(通常由硬件中断标记)都会运行(kernel/softirq.c)。

大部分真正的中断处理工作都是在这里完成的。在转换到 SMP 的早期阶段,只有“底半部”(BH),它们没有利用多个 CPU。不久之后,我们放弃了这种限制,转而使用了“软中断”。

include/linux/interrupt.h 列出了不同的软中断。一个非常重要的软中断是定时器软中断(include/linux/timer.h):您可以注册让它在一定时间内为您调用函数。

软中断通常很难处理,因为同一个软中断会同时在多个 CPU 上运行。因此,更常用的是任务队列(include/linux/interrupt.h):它们是动态可注册的(这意味着您可以拥有尽可能多的任务队列),并且它们还保证任何任务队列一次只在一个 CPU 上运行,尽管不同的任务队列可以同时运行。

警告

名称“任务队列”是误导性的:它们与“任务”无关。

您可以通过使用 in_softirq() 宏(include/linux/preempt.h)来判断是否在软中断(或任务队列)中。

警告

请注意,如果持有底半部锁,这将返回错误的结果。

一些基本规则

没有内存保护

如果您在用户上下文或中断上下文中损坏内存,整台机器都会崩溃。您确定您不能在用户空间完成您想要的操作吗?

没有浮点或 MMX

FPU 上下文未保存;即使在用户上下文中,FPU 状态可能与当前进程不对应:您会干扰某个用户进程的 FPU 状态。如果您真的想这样做,您必须显式保存/恢复完整的 FPU 状态(并避免上下文切换)。这通常是一个坏主意;首先使用定点算术。

严格的堆栈限制

根据配置选项,大多数 32 位架构的内核堆栈约为 3K 到 6K:在大多数 64 位架构上约为 14K,并且通常与中断共享,因此您无法全部使用它。避免在堆栈上进行深度递归和大型本地数组(应该动态分配它们)。

Linux 内核是可移植的

让我们保持这种状态。您的代码应该是 64 位兼容的,并且与大小端无关。您还应该尽量减少特定于 CPU 的内容,例如内联汇编应该清晰地封装并最小化,以便于移植。通常应该将其限制在内核树的体系结构相关部分。

ioctl:不编写新的系统调用

系统调用通常如下所示:

asmlinkage long sys_mycall(int arg)
{
        return 0;
}

首先,在大多数情况下,您不希望创建新的系统调用。您应该创建一个字符设备,并为其实现适当的 ioctl。这比系统调用更灵活,不必在每个体系结构的 include/asm/unistd.h 和 arch/kernel/entry.S 文件中输入,而且更有可能被 Linus 接受。

如果您的例程只是读取或写入某些参数,请考虑实现 sysfs() 接口。

在 ioctl 中,您处于用户上下文中的一个进程。当发生错误时,您返回一个负的 errno(参见 include/uapi/asm-generic/errno-base.h、include/uapi/asm-generic/errno.h 和 include/linux/errno.h),否则返回 0。

在休眠后,您应该检查是否发生了信号:处理信号的 Unix/Linux 方法是临时退出系统调用,并返回 -ERESTARTSYS 错误。系统调用入口代码将切换回用户上下文,处理信号处理程序,然后您的系统调用将被重新启动(除非用户禁用了它)。因此,您应该准备处理重新启动,例如,如果您正在操作某些数据结构的中间。

if (signal_pending(current))
        return -ERESTARTSYS;

如果您正在进行较长的计算:首先考虑用户空间。如果您真的想在内核中执行它,您应该定期检查是否需要放弃 CPU(请记住每个 CPU 有合作式多任务处理)。习惯用法:

cond_resched(); /* 将休眠 */

关于接口设计的简短说明:UNIX 系统调用的座右铭是“提供机制而不是策略”。

死锁的解决方案

除非:

  • 您处于用户上下文中。
  • 您不拥有任何自旋锁。
  • 您已启用中断(实际上,Andi Kleen 表示调度代码将为您启用它们,但这可能不是您想要的)。

您不能调用任何可能休眠的例程。请注意,某些函数可能会隐式休眠:常见的是用户空间访问函数(*_user)和没有 GFP_ATOMIC 的内存分配函数。

您应该始终使用编译内核时的 CONFIG_DEBUG_ATOMIC_SLEEP 选项,它会在您违反这些规则时发出警告。如果您违反了这些规则,最终会锁定您的计算机。

真的。

常见的内核编程例程

printk()

在 include/linux/printk.h 中定义

printk() 将内核消息输出到控制台、dmesg 和 syslog 守护进程。它对调试和错误报告很有用,并且可以在中断上下文中使用,但需要谨慎使用:如果控制台被大量的 printk 消息淹没,那么机器将无法使用。它使用的格式字符串大部分兼容 ANSI C printf,并使用 C 字符串连接来给它一个第一个“优先级”参数:

printk(KERN_INFO "i = %u\n", i);

参见 include/linux/kern_levels.h;其他 KERN_ 值;这些值被 syslog 解释为级别。特殊情况:要打印 IP 地址,请使用:

__be32 ipaddress;
printk(KERN_INFO "my ip: %pI4\n", &ipaddress);

printk() 内部使用 1K 缓冲区,并且不会捕获溢出。确保这足够大。

注意

当你开始在用户程序中将 printf 打成 printk 时,你就知道自己是一个真正的内核黑客了

标签:上下文,中断,linux,调用,黑客,内核,Linux,ChatGPT,include
From: https://www.cnblogs.com/pengdonglin137/p/17889306.html

相关文章

  • Linux分区方案、分区建议及手动分区操作步骤
    一.Linux分区方案介绍:1.标准分区:标准分区可以包含文件系统或交换空间,也能提供一个容器,用于软件RAID和LVM物理卷。2.BTRFS:Btrfs是一个具有几个设备相同的特征的文件系统。它能够处理和管理多个文件,大文件和大体积比的ext2,ext3和ext4文件系统。3.LVM(逻辑卷):创建一个LVM分区自动生成一......
  • 交叉编译工具 arm-none-linux-gnueabihf-gcc安装及思考
    1安装步骤A创建目录:/usr/local/armB将交叉编译器(压缩包)复制到该目录,在该目录下进行解压得到“gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf”的文件C打开/etc/profile文件添加环境变量       sudovi/etc/profile  exportPATH=......
  • Nexpose v6.6.230 for Linux & Windows - 漏洞扫描
    Nexposev6.6.230forLinux&Windows-漏洞扫描Rapid7VulnerabilityManagement,ReleaseDec07,2023请访问原文链接:https://sysin.org/blog/nexpose-6/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org您的本地漏洞扫描程序搜集通过实时覆盖整个网络,随......
  • JetBrains IDE 2023.3 (macOS, Linux, Windows) - 开发者工具
    JetBrainsIDE2023.3(macOS,Linux,Windows)-开发者工具AppCode,CLion,DataGrip,DataSpell,Fleet,GoLand,IntelliJIDEA,PhpStorm,PyCharm,Rider,RubyMine,WebStorm请访问原文链接:https://sysin.org/blog/jb-2023/,查看最新版。原创作品,转载请保留出处。作者主......
  • 发现工作负载使用的 Linux 内核子系统 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/admin-guide/workload-tracing.html发现工作负载使用的Linux内核子系统作者[email protected]@gmail.com维护者[email protected]要点了解构建和运行工......
  • 深入探讨Linux中的I/O重定向与进程管道
    在Linux系统中,I/O重定向和进程管道是强大的工具,为用户提供了灵活性和效率。本文将深入探讨这两个概念,解释它们的基本原理以及如何在实际工作中充分利用它们。I/O重定向什么是I/O重定向?在Linux中,I/O重定向是一种将一个命令的输入或输出流重定向到另一个地方的技术。这使得用户可......
  • 废弃的接口、语言特性、属性和约定 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/process/deprecated.html废弃的接口、语言特性、属性和约定在一个完美的世界中,将所有废弃的API实例转换为新的API并在单个开发周期内完全移除旧的API是可能的。然而,由于内核的规模、维护层次结构和时间安排,这种转换并不总是可行的......
  • Linux内核贡献成熟度模型 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/process/contribution-maturity-model.htmlLinux内核贡献成熟度模型背景作为2021年Linux内核维护者峰会的一部分,讨论了招募内核维护者以及维护者继任方面的挑战。其中一些结论包括,作为Linux内核社区的一部分,公司需要允许工程师作为工作......
  • 为什么不应该使用"volatile"类型的类 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/process/volatile-considered-harmful.html为什么不应该使用"volatile"类型的类C程序员通常认为volatile意味着变量可以在当前执行线程之外被改变;因此,当使用共享数据结构时,他们有时会倾向于在内核代码中使用它。换句话说,他们已经将volat......
  • 无涯教程-Linux - Unix - What is Shell?函数
    该Shell为您提供了UNIX系统的接口。它收集您的输入,并根据该输入执行程序。程序完成执行后,将显示该程序的输出。Shell是一个环境,我们可以在其中运行命令,程序和Shell脚本。Shell的样式不同,就像操作系统的样式不同。每种Shell程序都有其自己的一组公认的命令和功能。Shell提......