1)存储器管理概述
内存分配:为每道程序分配内存空间,分配时尽量提高内存的利用率
内存保护:保护进程间互不干扰,互相保密
地址映射:进程逻辑地址到内存物理地址的映射
内存扩充:提高内存利用率,扩大进程的内存空间。
存储器保护:
保护用户存储器中的数据的安全
要求:
防止用户对操作系统的影响
各用户进程应相互隔离
应禁止用户模式下对系统段进行写操作。
分页分段技术:
2)程序的装入和链接
将逻辑地址转化为物理地址。
绝对装入方式
可重定位装入
动态运行时装入方式
静态链接
装入时动态链接
运行时动态链接 多个进程可以公用一个dll,节省内存。
3)连续分配方式
动态分配 顺序表形式和链表形式
动态分区分配
4)内核空间
内核:操作系统相关功能实现
用户空间和内核空间是分开的。
32位Linux内核虚拟地址空间划分,0-3G为用户空间,3G-4G是内存空间
Linux系统中进程的用户空间是独立的,内核空间是共有的
为什么内核跟用户要分开?
有的指令是很危险的,将会导致系统崩溃
特权指令和非特权指令
Intel的cpu采用了四个级别ring0-ring3 .Linux只有两个级别
在内核态下,程序运行在内核地址空间中,cpu可以执行任何指令
在用户态下,进程运行在用户地址空间中,被执行的代码要受到cpu的诸多检查
程序运行在内核空间时就处于内核态,而进程运行在用户空间时处于用户态。 提高操作系统的稳定性及可用性
如何从用户空间进入内核空间?
所有的系统资源管理都是在内核空间中完成,可以通过内核提供的接口来完成这样的任务
用户态进入内核态总的来说有三种方式:系统调用,软中断,硬中断
脏牛漏洞
影响Linux的操作系统很长一段时间。
利用了内存的竞争条件。把所在用户组的编号改为0“root”用户的权限,就可以进行各种操作了,例如:订阅服务之类的
(1)mmap()函数进行内存映射,将一个文件或设备映射到内存的POSIX兼容的系统调用,从被映射的内存读取数据实际是从文件读取数据。
fork()会复制父进程的内容。大家同时在读的时候就用一份
写时复制:写的时候先复制到别的地方再写,如果不这样的话,许多进程同时写一个进程就有可能会发生错误。
(2)MAP_SHARED,MAP_PRIVATE和写时拷贝
一个文件的物理地址可以复制到不同的虚拟地址
MAP_PRIVATE:该文件被映射到调用进程专用的内存。
对内容所做的更改对其他进程是不可见的。
如果进程没有写入映射内存,就没有必要去做一个内存拷贝,只有写的时候才有这个必要
如果该进程尝试写入内存,则操作系统会分配一个新的物理内容快,并将该内容复制到新的内存。
映射的虚拟内存现在将指向新的物理内存。
写时拷贝:允许不同进程中的虚拟内存映射到相同物理内存页面(如果他们具有相同的内容)的技术
有可能会发生,b要修改的内容是a修改过后的,这就是竞争,有可能会产生一些越权的操作。
(3)抛弃复制的内存
madvise()提供有关从addr到addr+长度的内存的建议或知道
告诉内核不再需要这部分的地址空间,内核会释放这部分的地址空间并且更新页表
(4)映射只读文件
内存已修改,因为我们可以看到更改的内容,但是更改仅发生在映射内存的副本中
(5)脏牛漏洞
写要执行三个步骤
1.复制映射的内存
2.更新页表,以便虚拟内存指向新创建的物理内存
3.写入内存
上述的步骤不是原子的,可能会被打断。
在对一个内存进行写操作的时候,复制一个新的副本,然后在对其进行写操作之前,先用另一个进程去竞争,然后导致复制的内存被释放,这样再进行写操作的时候就是修改的是原本的文件了。
帧寄存器有两个,一个指向栈底,一个指向当前栈帧的指针
寄存器指向栈帧中的一个固定的地址
缓冲区溢出的防御措施
1.用更安全的函数,例如加了s的函数eg strcpy_s(),gets()
2.程序的静态分析:一般在命令行工具或者编辑器中实现,目的是在开发早期就告知开发者程序中潜在的不安全的代码
3.编程语言本身就可以检查,python,java
4.编译器将源代码转化为二进制代码,能够控制最后放二进制代码中的指令,因此编译器可以控制栈的布局,同时也能在二进制程序中插入验证栈完整性的命令。eg:stackshield 将返回地址备份到安全的地方。 stackGuard,在返回地址与缓冲区之间设置一个哨兵。
5.操作系统,部署在操作系统加载程序上的一个通用的防御措施是地址空间布局随机化。