-
本帖最后由 segFault 于 2024-5-3 14:54 编辑
1.
高速侧信道攻击(side-channel attacks)的原理基于这样的事实:计算机执行操作时,除了计算的主要结果之外,还会无意中泄露出一些额外的信息。这些信息可能是通过物理途径(如功耗、电磁波、声音、光线、温度或执行时间等)泄露的,它们可以被攻击者捕捉并用来推断出敏感信息,比如加密密钥。
时间攻击
时间攻击基于一个简单的观察:加密操作通常会根据不同的输入或密钥需要不同的处理时间。如果一个加密算法执行的时间随密码的某部分变化而变化,那么测量不同操作的执行时间可以提供关于密码的信息。例如,如果一个攻击者可以准确地测量某个加密操作的时间,并且知道这个时间会因为使用了某个特定的密钥比特而减少,那么他们就可以使用这种差异来推断密钥。
功耗分析攻击
功耗分析攻击利用的是电子设备在处理不同的数据时会消耗不同量的电能。通过精确地测量功耗,攻击者可以找到数据处理过程中的模式,并使用这些信息来推断出正在处理的数据,如加密密钥。最著名的功耗分析攻击包括简单功耗分析(SPA)和差分功耗分析(DPA)。
电磁攻击
电磁攻击依赖于电子设备在运行时会发射电磁信号。这些信号可以被捕捉,并可能泄露有关设备正在处理的信息。类似于功耗分析,通过分析电磁泄漏的模式,攻击者可能能够获取加密操作的信息。
声音攻击
设备在运行时会产生声波,这些声波可以包含有关设备操作的信息。例如,一个机械硬盘在访问不同区域的数据时会产生不同的声音。利用高度敏感的麦克风收集这些声音,攻击者可能能够找出正在进行的操作。
缓存攻击
如前所述,缓存攻击是专门针对计算机缓存的一种侧信道攻击。它们利用在多任务环境中共享缓存的行为,通过观察缓存访问的时间差异来推断其他程序的行为和数据。例如,如果一个攻击者能够监控到访问共享库函数(如加密算法中的某个函数)时的缓存加载时间,他们可能能够获取有关加密操作及其密钥的信息。
侧信道攻击的关键在于,它们并不是直接攻击算法的数学基础,而是利用实现该算法的系统的物理实现缺陷来获取敏感信息。因此,即使算法在数学上是安全的,它们的物理实现也可能受到侧信道攻击的威胁。解决侧信道攻击通常需要注意硬件的设计、加密算法的实现方式以及软件的运行环境。
CPU熔断漏洞(如Meltdown和Spectre)利用现代处理器的性能特性,如乱序执行和投机执行(speculative execution),来迫使处理器"提前"执行某些操作,从而可能访问到本不应当被当前进程访问的数据。在这些攻击中,尽管非法操作(比如用户态访问内核空间的内存)最终会被处理器检测到并引发异常,但投机执行的结果仍然会影响处理器的状态(比如缓存),这就提供了侧信道的机会。
为了利用这些漏洞而不让非法内存访问导致进程终止,攻击者可以采用以下步骤:
异常处理:攻击代码可以准备一个异常处理程序来捕获这种访问违规(如果发生)。当访问内核空间的非法内存时,CPU将触发一个异常,但攻击者的异常处理程序可以避免进程终止。
侧信道分析:即使访问引发了异常,乱序或投机执行的结果可以通过侧信道(例如高速缓存侧信道)来观察。例如,如果投机性执行取决于敏感信息,并且这个执行改变了CPU的缓存状态,那么即使异常已经废除了非法操作的结果,缓存的状态变化仍然可以通过缓存侧信道来测量。
传输时间分析:攻击者可以测量读取内存位置所需的时间。如果内存位置已经因为投机执行而被加载到缓存中,访问该位置的时间将明显减少。这种时间差异可以用来推断哪些数据可能被加载到缓存中。
数据重构:通过反复执行上述步骤并测量不同数据加载操作的速度,攻击者可以逐渐重构出内存中的数据,即使这些数据是由操作系统内核保护的。
综上所述,尽管直接的非法内存访问会被检测并阻止,但是通过细致的异常处理和侧信道分析,攻击者仍然能够利用硬件层面的漏洞来间接地推断受保护的内存空间中的信息。 解决这类问题需要硬件制造商提供固件更新或操作系统制造商提供补丁来缓解这些硬件漏洞的影响。
熔断漏洞(Meltdown)攻击主要针对现代处理器的乱序执行和投机执行(speculative execution)的特性。这些特性被设计用来提高处理器的性能,但同时它们也引入了潜在的安全风险。熔断漏洞允许攻击者绕过硬件的内存隔离保护,从而访问系统内存中的敏感数据,包括其他程序、操作系统内核以及物理内存中的信息。
3
熔断漏洞攻击的原理:
投机执行: 现代CPU为了提高性能,会使用投机执行技术。当遇到分支指令时,CPU会尝试预测分支的方向,并在确认真实路径之前,预先执行这一路径上的指令。
乱序执行: 另一种提升性能的技术是乱序执行,即CPU会在不改变程序执行结果的前提下改变指令的执行顺序。这使得CPU可以不必按照程序指定的顺序严格执行指令。
异常处理: 当投机执行的过程中执行了非法操作(如用户态程序访问系统内核数据),CPU会引发异常。正常情况下,这会导致非法操作的结果被抛弃,从而保护系统安全。
熔断漏洞攻击的过程:
触发投机执行: 攻击者构造一段代码,该代码尝试从受保护的内存区域读取数据。由于权限不足,这种读取正常情况下会引发访问违规的异常。
利用侧信道: 虽然非法操作的结果会因异常而被废除,但是在投机执行期间,读取的数据会短暂加载到CPU的缓存中。这导致缓存的状态发生了变化。
测量缓存延迟: 攻击者通过测量访问内存的时间来判断数据是否在缓存中。如果数据被缓存,则访问时间会显著减少,这允许攻击者推断出被投机执行读取的数据。
通过重复上述步骤,攻击者可以逐渐提取出存储在受保护内存区域的敏感数据,如密码、加密密钥等。熔断攻击主要是因为处理器为了性能优化而采用的投机执行机制,导致了数据的非法泄露。
针对此类攻击的防御通常需要硬件和操作系统级别的更新与补丁,例如关闭或限制投机执行特性,以及提高内核与用户空间之间的隔离。
-
1 函数调用
在ARM64架构下,当函数`main()`调用`func1()`,然后`func1()`调用`func2()`时,函数栈(call stack)的布局大致如下所示:
```
|-----------------|
-
1. kdump原理
Kdump是Linux内核的崩溃转储工具,它允许系统在遇到致命错误时捕获内核转储(也称为核心转储或崩溃转储)。这个转储可以用于事后分析,以确定导致系统崩溃的原因。Kdump的工作原理可以分为以下几个步骤:
1. **预备阶段**:
- Kdump配置一个专门的崩溃内核(crash kernel),这个内核的大小远小于主内核,并且在系统启动时被加载到内存中。
- 崩溃内核位于主内核可访问的内存区域内,这样在主内核崩溃时,它仍然可以运行。
2. **触发阶段**:
- 当主内核检测到无法恢复的错误时(比如内存访问违规、不可处理的硬件错误等),它会通过特殊的机制将控制权交给崩溃内核。
- 崩溃内核接管系统后,会停止所有非必要的硬件和软件操作,确保内存内容不会被覆盖。
3. **转储阶段**:
- 崩溃内核使用预先配置的内存映射和转储设备(通常是磁盘上的一个文件),将主内核的内存映像写入转储文件中。
- 转储过程中可能会使用到kexec系统调用,它允许绕过常规的引导加载程序直接加载和运行另一个内核。
4. **重启阶段**:
- 完成转储后,崩溃内核可以选择重启系统,以便进行后续的分析工作。
- 系统重启后,用户可以使用像gdb(GNU调试器)这样的工具来分析转储文件,诊断问题所在。
Kdump是一个强大的故障排查工具,它允许系统管理员在发生严重错误时收集关键信息,有助于快速定位问题并采取相应的修复措施。
2. x86_64架构里,函数的传参方式
在x86_64架构中,函数参数通常通过寄存器传递。这种调用约定被称作System V AMD64 ABI(Application Binary Interface)。以下是传递参数的一般规则:
1. **第一个整数或指针参数**:放在`rdi`寄存器中。
2. **第二个整数或指针参数**:放在`rsi`寄存器中。
3. **第三个整数或指针参数**:放在`rdx`寄存器中。
4. **第四个整数或指针参数**:放在`rcx`寄存器中。
5. **第五个、第六个和第七个整数或指针参数**:分别放在`r8`、`r9`和`r10`寄存器中。
如果有超过七个的参数,剩余的参数将通过栈传递。函数返回值通常也通过这些寄存器返回,具体取决于返回类型:
- **整型和指针返回值**:通过`rax`寄存器返回。
- **浮点型和向量返回值**:通过`xmm0`寄存器返回。
对于结构体类型的返回值,如果它小于或等于128位(16字节),则通过`rax`寄存器返回;如果大于128位,则通过栈返回。
在调用函数之前,调用者负责将参数按正确的顺序放入相应的寄存器中。函数内部通常不会修改`rdi`、`rsi`、`rdx`、`rcx`、`r8`、`r9`和`r10`寄存器的值,以确保调用者能够从这些寄存器中检索参数。
需要注意的是,有些情况下,如变量参数(使用`...`表示的参数),参数会通过栈传递,而不是寄存器。此外,某些特定的系统调用或 库函数可能使用不同的调用约定,所以在实际编程中需要参考相应的文档或规范。
3. main->func1()->func2() 函数栈
在x86_64架构下,当函数`main()`调用`func1()`,然后`func1()`调用`func2()`时,函数栈(call stack)的布局大致如下所示:
```
|-----------------|
-
linux内核调试
linux o0优化有什么好处,
o0优化,对代码没有任何优化,实际运行下来,性能是要低于o2优化的,但是,这里没有编译优化带来的代码执行顺序调整,以及对外隐藏变量与代码细节的情况,可以更方便的调试
什么是加载地址、运行地址和链接地址
加载地址(Load Address): 加载地址是指程序在被加载到内存中时的起始地址。当将程序从存储介质(如磁盘)加载到内存时,需要指定程序在内存中的位置。加载地址决定了程序在内存中的物理位置,同时也确定了程序中各个部分(如代码段、数据段等)在内存中的偏移量。
运行地址(Runtime Address): 运行地址是指程序在内存中实际执行时的地址。当程序开始执行时,加载地址会被转换为运行地址。运行地址是CPU实际访问内存中指令和数据的地址。由于操作系统和硬件的虚拟内存管理机制,运行地址可能与加载地址不同。
链接地址(Link Address): 链接地址是指将多个目标文件或库文件合并生成可执行文件时,各个目标文件在合并后的文件中的基地址。在编译和链接过程中,每个目标文件都有自己的加载地址,链接地址是将这些加载地址通过链接器(Linker)进行调整和合并后的结果。
位置无关指令,位置有关指令
位置无关的汇编指令: 位置无关的汇编指令是一种设计方式,使得汇编程序可以在内存中的任意位置执行,而不依赖于指令的实际物理位置。这种指令通常用于可执行文件或共享库等需要在不同的内存地址加载和执行的情况。位置无关的汇编指令使用相对地址或基于寄存器的偏移量来引用代码和数据,以避免对特定地址的依赖。
位置有关的汇编指令: 位置有关的汇编指令是一种依赖于指令在内存中具体位置的指令。这些指令使用绝对地址来引用代码和数据,指定了指令在内存中的确切位置。位置有关的汇编指令通常用于单独运行的可执行文件,其中指令的加载地址是固定的,没有加载到其他内存地址的需求。
-
发生硬件中断后,ARM64处理器做了哪些事情?
在ARM64架构中,当发生硬件中断时,处理器将执行以下基本步骤来处理这一事件:
中断识别: 处理器检测到外部或内部事件引发的硬件中断信号。
上下文保存: 在跳转至中断处理程序之前,处理器会自动保存当前执行上下文的关键部分,这通常包括程序计数器(PC)、状态寄存器(如当前程序状态寄存器Current Program Status Register, CPSR)和某些其他寄存器。这个过程通常由处理器硬件自动完成,并且保存到堆栈或专用的保存区域。
中断向量表: CPU利用中断向量表或异常向量表来确定中断服务程序的地址。在ARM64中,这个向量表通常位于一个固定的地址,或者是由一个系统寄存器指定的地址。
模式切换与安全状态: 处理器可能会切换到一个特定的异常级别(比如从EL0切换到EL1),并进入一个安全的状态来执行中断服务例程(ISR)。这可以包括改变堆栈指针和切换到特权模式。
中断服务程序(ISR)执行: 一旦处理器通过中断向量获取了中断服务程序的地址,它会跳转到该地址开始执行。ISR的责任是快速识别中断源,执行必要的处理来响应这一中断,比如读取硬件设备的数据或者更新状态信息等。
清除中断标志:在处理了实际的中断之后,ISR需要告诉中断控制器或者相关硬件中断已经被处理。这通常涉及到写入特定的寄存器以清除或重置中断请求状态。
恢复执行上下文: ISR完成后,需要恢复之前保存的执行上下文,以便处理器能够返回到中断发生前正在执行的任务或程序。这包括恢复寄存器的值和程序状态。
中断返回:最后,处理器执行一个特殊的中断返回指令(比如ERET在ARM64中),这一指令会将处理器的执行流从ISR返回到被中断的程序,并恢复执行的状态,接着从中断点之后继续执行程序。
以上步骤是在很高的抽象层次上描述了硬件中断的处理过程,具体的实现细节可能因不同的ARM64实现而异。在实际的操作系统中,中断处理程序会与操作系统的内核紧密配合,确保有效管理硬件资源和调度。
硬件中断号和Linux内核的IRQ号是如何映射的?
在Linux内核中,硬件中断号与内核的IRQ号之间的映射关系是由中断控制器和内核的中断管理子系统共同协调的。这个映射关系的建立过程大致如下:
中断控制器: 硬件设备通过中断线(也称为中断通道)与中断控制器相连。每个硬件设备产生的中断信号都被分配了一个唯一的硬件中断号(也称为中断请求线路编号IRQ number),这通常是由硬件设计确定的。
系统启动: 在系统启动时,内核会识别并初始化系统中所有的硬件设备和中断控制器。作为初始化过程的一部分,内核会查询中断控制器,了解其管理的硬件中断号。
映射表建立: 内核维护一个映射表来关联硬件中断号和内核管理的IRQ号。在这个过程中,内核可能会对硬件中断号进行重新映射或分配一个内核的IRQ号。这个过程可以涉及到动态分配或固定映射。
设备驱动: 设备驱动程序在初始化时会请求一个IRQ号来处理与该设备相关的中断。驱动程序通过调用内核提供的API函数如 request_irq() 来注册其中断处理函数,并将其与一个特定的IRQ号关联起来。在这个调用过程中,内核会将驱动程序请求的IRQ号与应的硬件中断号相关联。
IRQ域(IRQ Domain): 在复杂的系统或多级中断控制器架构中,Linux内核可能使用IRQ域来管理不同中断控制器和不同类型的中断之间的映射关系。IRQ域提供了一个从硬件中断号到内核IRQ号的抽象层。
处理硬件中断: 当硬件设备产生一个中断时,中断控制器发送信号到CPU。CPU根据硬件中断号通过内核的映射表找到对应的内核IRQ号,并调用与该IRQ号关联的中断处理函数。
整个映射过程是由操作系统内核自动管理的,确保了即使在硬件中断号与内核IRQ号不一致的情况下,设备驱动程序也能正确处理中断。这样做允许操作系统更灵活地管理资源,同时也隐藏了硬件的复杂性,使得驱动程序编写者无需考虑具体的硬件细节。
一个硬件中断发生后,Linux内核如何响应并处理该中断?
在Linux内核中,当一个硬件中断发生后,以下是内核响应并处理该中断的基本步骤:
中断触发: 特定的硬件设备触发中断,通过发送信号到中断控制器或直接到CPU(取决于系统的硬件设计)。
中断控制器处理: 如果存在中断控制器,它将识别中断请求并将其发送至CPU。在支持高级可编程中断控制器(APIC)的系统中,中断可以直接送达一个特定的CPU核心。
上下文保存: CPU接收到中断后,会自动保存当前处理状态(如寄存器内容等),以便中断处理完成后能够恢复当前任务的执行。
中断向量和服务程序: CPU使用中断向量表来确定应当执行的中断服务程序(ISR)的地址,并跳转到该地址执行相应的ISR。中断向量表是在系统启动时由内核设置的。
中断处理函数(ISR): 一旦执行流跳转到正确的ISR,内核将执行与该中断相关联的处理函数。这通常是由设备驱动程序注册的一个函数,它会执行必要的任务来处理中断,如读取数据、重置硬件状态或发送信号等。
中断底半部(Bottom Halves)处理: 为了最小化中断服务例程中的延迟,Linux通常会将中断处理分为两部分:顶半部(Top Half)和底半部(Bottom Half)。顶半部是紧急处理部分,而底半部则处理那些不那么紧急的任务。常见的底半部处理机制包括任务队列、软中断(softirqs)和工作队列。
结束中断处理: 一旦中断处理程序完成其工作,会执行特定的指令来通知中断控制器中断已经处理完毕,这通常涉及写操作到中断控制器的某个寄存器来清除中断标志,以避免重复处理同一个中断。
恢复上下文: 处理完中断后,系统会恢复在中断发生时保存的状态,以便继续执行被中断的进程或开始执行另一个进程(如果中断后的调度决定了上下文切换)。
上下文切换(如果需要): 如果在处理中断的过程中,有更高优先级的进程需要运行,或者当前进程的时间片已经用完,内核可能会执行上下文切换,切换到另一个进程运行。
这个过程是由操作系统内核自动管理的。对于设备驱动开发者来说,他们需要确保其注册的ISR能够快速执行且能够正确地响应和处理相关设备发出的中断。
-
1. 在arm架构中独占访问内存
在ARM架构中,实现对内存的独占访问通常涉及使用LDREX(Load-Exclusive)和STREX(Store-Exclusive)指令。这些指令用于实现锁-自由(lock-free)同步原语,如原子操作和互斥锁。
当你使用LDREX指令时,它会读取一个值,同时告诉内存系统你打算执行一个独占式的存储(使用STREX)到同一地址。如果在执行LDREX和STREX之间,另一个处理器试图访问该内存地址,那么STREX会失败,并返回一个非零值,表明你需要重新尝试整个操作。
2. 原子操作函数
1. atomic_cmpxchg()
这个函数执行一个原子的比较并交换操作。
它通常接收三个参数:一个内存位置、一个预期旧值以及一个新值。
操作的基本思路是,只有当内存位置的当前值与预期旧值相匹配时,才将内存位置的值更新为新值。
如果操作成功,即内存位置的原始值与预期旧值匹配,它通常返回true或者原始值。
如果操作失败,即内存位置的原始值不匹配,它通常返回false或者当前内存位置的实际值。
它是实现锁-自由数据结构和同步原语的关键操作
2. atomic_xchg()
这个函数执行一个原子的交换操作。
它通常接收两个参数:一个内存位置和一个新值。
它将内存位置的当前值替换为新值,并返回内存位置的旧值。
与atomic_cmpxchg()不同,atomic_xchg()不关心内存位置的旧值是什么,它无条件地进行交换操作。
3. 存储释放指令
在ARM64(也称为AArch64)架构中,内存顺序保持是通过内存栅栏(Memory Barriers,也称为Memory Fences)来实现的,这些栅栏确保在它们之前的内存操作完成后,其后的内存操作才能开始。CAS(Compare-And-Swap)指令本身不直接定义在ARMv8指令集中,但类似的功能可以通过一系列原子指令完成,例如LDAXR/STLXR(加载获取/存储释放独占对)。这些指令通常用于实现CAS操作。
加载获取(Load-Acquire): 当执行加载获取操作时,它保证了所有后续的内存访问(读或写)在获取操作完成后执行。这意味着获取操作会创建一个内存屏障,确保在这条指令之后的所有读取操作都能看到在它之前的写操作。
存储释放(Store-Release): 相对于加载获取,存储释放操作确保了它之前的所有内存写操作都完成后,该释放操作才会执行。这保证了在存储释放写入之前的所有内存操作对其他处理器都是可见的。
-
个人信息无误,确认可以完成阅读计划和打卡任务
-
个人信息无误,已知晓需自己支付邮费
-
板卡:基于stm32f103的ufun学习板(第二版本)
理由:初接触嵌入式,需要这样一个外设多资料多的设备,用来研究各种通讯协议以及开发基础