操作系统原理详解(四):作业管理、死锁、操作系统安全

文章概述

本篇主要讲解第六章和第七章和第八章:操作系统作业管理、死锁、操作系统安全。其余章节请参考专栏其他篇幅。

目录

  1. 操作系统概述
  2. 进程管理
  3. 存储管理
  4. 设备管理
  5. 文件管理
  6. 作业管理
  7. 死锁
  8. 操作系统安全
  9. 现代操作系统技术
  10. 操作系统实例分析

六、作业管理

作业管理是操作系统的重要功能,负责管理用户提交的作业,包括作业的提交、调度、执行和完成。作业管理连接用户和系统,是用户使用计算机的桥梁。


6.1 作业管理概述

作业管理是操作系统对用户作业进行管理的功能模块。在批处理系统中,作业管理尤为重要;在现代交互式系统中,作业管理的概念仍然存在,但形式有所变化。

6.1.1 作业的概念

作业的定义

作业(Job)是用户提交给计算机系统的一个相对独立的工作单位,通常包含程序、数据和作业说明书。

作业:

定义:
  - 用户提交给系统的一个完整任务
  - 包含完成该任务所需的所有信息
  - 系统处理的基本单位

特点:
  1. 独立性:
     - 作业是相对独立的工作单位
     - 可以独立完成
     - 不依赖其他作业

  2. 完整性:
     - 包含完成任务的完整信息
     - 程序、数据、控制信息
     - 可以独立执行

  3. 批处理性:
     - 在批处理系统中重要
     - 可以批量提交
     - 系统自动处理

形象比喻:

如果把计算机系统比作一个工厂:

  • 作业 = 一个完整的生产订单(包含产品规格、原材料、生产步骤)
  • 程序 = 生产步骤说明(如何生产)
  • 数据 = 原材料(需要处理的数据)
  • 作业管理 = 订单管理系统(接收订单、安排生产、跟踪进度)

作业 vs 进程

作业和进程是不同层次的概念。

作业 vs 进程:

作业:
  - 用户角度的概念
  - 用户提交的任务
  - 可能包含多个程序
  - 从提交到完成

进程:
  - 系统角度的概念
  - 程序的执行实例
  - 系统调度的单位
  - 从创建到终止

关系:
  - 一个作业可以包含多个进程
  - 作业是进程的集合
  - 作业完成后,相关进程终止

例子:
  作业:编译C程序
    包含:
      - 编译程序(进程1)
      - 链接程序(进程2)
      - 运行程序(进程3)
  
  一个作业 → 多个进程

6.1.2 作业的组成

一个完整的作业通常由以下几部分组成。

作业的组成:

1. 程序:
   - 可执行的程序代码
   - 完成作业的主要逻辑
   - 例如:编译程序、计算程序

2. 数据:
   - 程序处理的数据
   - 输入数据文件
   - 例如:源代码、数据文件

3. 作业说明书(Job Control Language,JCL):
   - 作业的控制信息
   - 描述作业的执行要求
   - 例如:资源需求、执行步骤

4. 作业控制块(JCB,Job Control Block):
   - 系统为作业创建的数据结构
   - 记录作业的状态和信息
   - 用于作业管理

作业说明书(JCL)

作业说明书描述作业的执行要求和控制信息。

作业说明书(JCL):

内容:
  1. 作业标识:
     - 作业名
     - 作业号
     - 用户标识

  2. 资源需求:
     - CPU时间
     - 内存大小
     - 外设需求
     - 文件需求

  3. 执行步骤:
     - 作业的执行步骤
     - 程序执行顺序
     - 步骤间的依赖关系

  4. 输入输出:
     - 输入文件
     - 输出文件
     - 错误处理

例子(简化JCL):
  //JOB1 JOB USER=USER1
  //STEP1 EXEC PGM=COMPILE
  //INPUT DD DSN=SOURCE.C
  //OUTPUT DD DSN=OBJECT.O
  //STEP2 EXEC PGM=LINK
  //INPUT DD DSN=OBJECT.O
  //OUTPUT DD DSN=PROGRAM.EXE
  //STEP3 EXEC PGM=PROGRAM.EXE
  //INPUT DD DSN=DATA.DAT
  //OUTPUT DD DSN=RESULT.OUT

说明:
  - JOB1:作业名
  - STEP1, STEP2, STEP3:执行步骤
  - PGM:程序名
  - DD:数据定义
  - DSN:数据集名

作业控制块(JCB)

作业控制块是系统为作业创建的数据结构,记录作业的所有信息。

作业控制块(JCB):

结构:
  struct job_control_block {
      // 作业标识
      char job_name[64];       // 作业名
      int job_id;              // 作业ID
      int user_id;             // 用户ID
      
      // 作业状态
      int job_status;          // 作业状态
      time_t submit_time;      // 提交时间
      time_t start_time;       // 开始时间
      time_t finish_time;      // 完成时间
      
      // 资源需求
      int cpu_time;            // CPU时间需求
      int memory_size;         // 内存需求
      int priority;            // 优先级
      
      // 程序和数据
      char program_name[256];  // 程序名
      char data_files[][256];  // 数据文件列表
      
      // 执行步骤
      struct step steps[];     // 执行步骤
      
      // 其他信息
      int exit_code;           // 退出码
      char error_message[512]; // 错误信息
  };

作用:
  - 系统管理作业的数据结构
  - 记录作业的所有信息
  - 用于作业调度和管理

6.1.3 作业的状态

作业在执行过程中会经历多个状态,状态转换反映了作业的生命周期。

作业状态:

1. 提交态(Submitted):
   - 用户提交作业
   - 作业进入系统
   - 等待被调度

2. 后备态(Backup):
   - 作业在磁盘上等待
   - 已进入作业队列
   - 等待作业调度

3. 运行态(Running):
   - 作业被调度
   - 创建进程执行
   - 正在执行中

4. 完成态(Completed):
   - 作业执行完成
   - 输出结果
   - 等待清理

5. 终止态(Terminated):
   - 作业被终止
   - 可能正常完成或异常终止
   - 资源已回收

作业状态转换

作业状态转换:

状态转换图:
  提交态
    ↓(进入系统)
  后备态
    ↓(作业调度)
  运行态
    ↓(执行完成/异常)
  完成态
    ↓(清理)
  终止态

详细转换:
  1. 提交态 → 后备态:
     - 用户提交作业
     - 系统接收作业
     - 创建JCB
     - 加入后备队列

  2. 后备态 → 运行态:
     - 作业调度程序选择作业
     - 分配资源
     - 创建进程
     - 开始执行

  3. 运行态 → 完成态:
     - 作业执行完成
     - 正常结束或异常终止
     - 保存结果

  4. 完成态 → 终止态:
     - 输出结果给用户
     - 回收资源
     - 删除JCB
     - 作业完全结束

作业状态转换示例

作业状态转换示例:

时间线:
  T1: 用户提交作业
      状态:提交态
      操作:创建JCB,加入系统

  T2: 系统接收作业
      状态:后备态
      操作:加入后备队列,等待调度

  T3: 作业调度程序选择该作业
      状态:运行态
      操作:分配资源,创建进程,开始执行

  T4: 作业执行中
      状态:运行态
      操作:进程执行,使用资源

  T5: 作业执行完成
      状态:完成态
      操作:保存结果,准备输出

  T6: 输出结果,清理资源
      状态:终止态
      操作:删除JCB,作业结束

作业状态的管理

作业状态管理:

状态记录:
  - JCB中记录当前状态
  - 状态转换时更新JCB
  - 系统可以查询作业状态

状态队列:
  - 后备队列:所有后备态作业
  - 运行队列:所有运行态作业
  - 完成队列:所有完成态作业

状态查询:
  - 用户可以查询作业状态
  - 系统提供状态查询命令
  - 例如:qstat, jobs等

状态显示:
  作业ID    作业名    状态      提交时间    开始时间
  ──────────────────────────────────────────────
  1001      job1      运行中     10:00       10:05
  1002      job2      后备       10:10       -
  1003      job3      完成       09:50       09:55

6.2 作业调度

作业调度(Job Scheduling)是作业管理的核心,负责从后备队列中选择作业,为其分配资源,创建进程,使其进入运行态。作业调度是高级调度,决定哪些作业可以进入系统执行。

6.2.1 作业调度的功能

作业调度程序(Job Scheduler)需要完成以下主要功能。

作业调度功能:

1. 作业选择:
   - 从后备队列中选择作业
   - 根据调度算法选择
   - 考虑系统资源

2. 资源分配:
   - 为作业分配内存
   - 分配I/O设备
   - 分配其他资源

3. 进程创建:
   - 为作业创建进程
   - 初始化进程环境
   - 启动进程执行

4. 作业控制:
   - 监控作业执行
   - 处理作业完成
   - 回收资源

5. 作业管理:
   - 维护作业队列
   - 更新作业状态
   - 记录作业信息

作业调度的时机

作业调度时机:

1. 新作业提交:
   - 用户提交新作业
   - 可能触发调度
   - 检查是否可以立即执行

2. 作业完成:
   - 作业执行完成
   - 释放资源
   - 可以调度新作业

3. 系统资源变化:
   - 资源释放
   - 可以调度等待的作业
   - 提高资源利用率

4. 定时调度:
   - 定期检查
   - 调度等待的作业
   - 平衡系统负载

作业调度的目标

作业调度目标:

1. 提高系统吞吐量:
   - 处理更多作业
   - 提高系统效率
   - 充分利用资源

2. 提高资源利用率:
   - 充分利用CPU
   - 充分利用内存
   - 充分利用I/O设备

3. 公平性:
   - 公平对待所有作业
   - 避免作业饥饿
   - 平衡用户需求

4. 响应时间:
   - 减少作业等待时间
   - 提高响应速度
   - 改善用户体验

5. 系统稳定性:
   - 避免系统过载
   - 保证系统稳定
   - 防止资源耗尽

6.2.2 作业调度算法

作业调度算法决定如何从后备队列中选择作业。不同的算法有不同的特点和适用场景。

1. 先来先服务(FCFS,First Come First Served)

先来先服务(FCFS):

算法:
  - 按照作业提交的顺序
  - 先提交的先执行
  - 简单公平

特点:
  - 非抢占式
  - 简单易实现
  - 公平但效率可能不高

例子:
  后备队列:
    作业1(提交时间10:00,执行时间2小时)
    作业2(提交时间10:05,执行时间10分钟)
    作业3(提交时间10:10,执行时间30分钟)
  
  执行顺序:作业1 → 作业2 → 作业3
  
  问题:
    - 作业2和作业3需要等待作业1完成
    - 短作业等待长作业
    - 平均等待时间长

优点:
  - 实现简单
  - 公平
  - 适合批处理系统

缺点:
  - 短作业可能等待长作业
  - 平均等待时间长
  - 不适合交互式系统

2. 短作业优先(SJF,Shortest Job First)

短作业优先(SJF):

算法:
  - 选择执行时间最短的作业
  - 优先执行短作业
  - 减少平均等待时间

特点:
  - 非抢占式或抢占式
  - 理论最优(非抢占式)
  - 但需要知道执行时间

例子:
  后备队列:
    作业1(执行时间2小时)
    作业2(执行时间10分钟)
    作业3(执行时间30分钟)
  
  执行顺序:作业2 → 作业3 → 作业1
  
  优势:
    - 短作业先执行
    - 平均等待时间短
    - 系统吞吐量高

优点:
  - 平均等待时间最短(理论)
  - 系统吞吐量高
  - 适合批处理系统

缺点:
  - 长作业可能饥饿
  - 需要知道执行时间(难以预测)
  - 不适合交互式系统

3. 优先级调度(Priority Scheduling)

优先级调度:

算法:
  - 每个作业有优先级
  - 选择优先级最高的作业
  - 体现作业重要性

优先级确定:
  1. 静态优先级:
     - 作业提交时确定
     - 运行期间不变
     - 简单但不灵活

  2. 动态优先级:
     - 运行期间可以变化
     - 根据等待时间等因素调整
     - 灵活但复杂

优先级因素:
  - 用户优先级
  - 作业类型
  - 资源需求
  - 等待时间

例子:
  后备队列:
    作业1(优先级3,执行时间2小时)
    作业2(优先级1,执行时间10分钟)
    作业3(优先级4,执行时间30分钟)
  
  执行顺序:作业3 → 作业1 → 作业2
  (优先级高的先执行)

优点:
  - 灵活
  - 可以体现重要性
  - 适合多种场景

缺点:
  - 低优先级可能饥饿
  - 需要防止优先级反转
  - 需要合理设置优先级

4. 高响应比优先(HRRN,Highest Response Ratio Next)

高响应比优先(HRRN):

算法:
  - 计算每个作业的响应比
  - 选择响应比最高的作业
  - 平衡等待时间和执行时间

响应比计算:
  响应比 = (等待时间 + 执行时间) / 执行时间
         = 1 + 等待时间 / 执行时间

特点:
  - 等待时间越长,响应比越高
  - 执行时间越短,响应比越高
  - 平衡公平性和效率

例子:
  当前时间:10:30
  后备队列:
    作业1(提交时间10:00,执行时间2小时)
      等待时间:30分钟
      响应比 = 1 + 30/120 = 1.25
    作业2(提交时间10:20,执行时间10分钟)
      等待时间:10分钟
      响应比 = 1 + 10/10 = 2.0
    作业3(提交时间10:25,执行时间30分钟)
      等待时间:5分钟
      响应比 = 1 + 5/30 = 1.17
  
  执行顺序:作业2 → 作业1 → 作业3
  (响应比高的先执行)

优点:
  - 平衡等待时间和执行时间
  - 避免长作业饥饿
  - 短作业也有优势

缺点:
  - 需要计算响应比
  - 需要知道执行时间
  - 实现稍复杂

5. 多级队列调度(Multilevel Queue)

多级队列调度:

算法:
  - 将作业分为多个队列
  - 每个队列有不同优先级
  - 高优先级队列优先调度
  - 队列内可以使用不同算法

队列分类:
  1. 系统作业队列(最高优先级):
     - 系统作业
     - 使用FCFS或优先级

  2. 交互作业队列:
     - 交互式作业
     - 使用时间片轮转

  3. 批处理作业队列(最低优先级):
     - 批处理作业
     - 使用FCFS或SJF

调度策略:
  - 高优先级队列优先
  - 队列空时才调度下一队列
  - 队列内使用相应算法

例子:
  队列1(系统作业,FCFS):
    作业A, 作业B
  
  队列2(交互作业,RR,时间片=10ms):
    作业C, 作业D, 作业E
  
  队列3(批处理,SJF):
    作业F, 作业G
  
  调度:队列1 → 队列2 → 队列3

优点:
  - 灵活
  - 适应不同作业类型
  - 平衡各种需求

缺点:
  - 实现复杂
  - 需要合理分类
  - 低优先级可能饥饿

作业调度算法对比

作业调度算法对比:

算法          平均等待时间  公平性    实现复杂度  适用场景
─────────────────────────────────────────────
FCFS          长            好        简单        批处理
SJF           最短          差        中等        批处理
优先级        中            中        中等        通用
HRRN          较短          较好      中等        批处理
多级队列      中            较好      复杂        通用系统

现代系统:
  - 交互式系统:主要使用进程调度
  - 批处理系统:使用作业调度
  - 现代系统:作业调度概念弱化

6.2.3 作业调度与进程调度的关系

作业调度和进程调度是不同层次的调度,它们相互配合,共同完成系统调度任务。

作业调度 vs 进程调度:

层次关系:
  作业调度(高级调度)
    ↓
  进程调度(低级调度)

  作业调度决定哪些作业进入系统
  进程调度决定哪个进程获得CPU

功能对比:
  作业调度:
    - 从外存选择作业进入内存
    - 创建进程
    - 频率低(分钟级)

  进程调度:
    - 从内存选择进程分配CPU
    - 进程切换
    - 频率高(毫秒级)

关系:
  - 作业调度为进程调度提供进程
  - 进程调度执行作业的任务
  - 两者配合完成作业执行

三级调度系统

现代操作系统通常采用三级调度系统。

三级调度系统:

1. 高级调度(作业调度):
   - 从外存选择作业进入内存
   - 创建进程
   - 频率:分钟级或更长

2. 中级调度(内存调度):
   - 将进程在内存和外存间换入换出
   - 挂起和激活进程
   - 频率:秒级

3. 低级调度(进程调度):
   - 从就绪队列选择进程分配CPU
   - 进程切换
   - 频率:毫秒级

调度层次:
  外存(作业) → 高级调度 → 内存(进程) → 
  中级调度(换入换出) → 就绪队列 → 
  低级调度 → CPU执行

现代系统:
  - 交互式系统:高级调度弱化
  - 主要使用进程调度
  - 批处理系统:三级调度完整

作业调度与进程调度的协调

作业调度与进程调度的协调:

工作流程:
  1. 用户提交作业
     ↓
  2. 作业调度:选择作业,创建进程
     ↓
  3. 进程进入就绪队列
     ↓
  4. 进程调度:选择进程,分配CPU
     ↓
  5. 进程执行
     ↓
  6. 进程完成,作业完成
     ↓
  7. 作业调度:回收资源,清理作业

协调机制:
  - 作业调度控制进入系统的作业数
  - 进程调度控制CPU的使用
  - 两者配合保证系统稳定

资源管理:
  - 作业调度:管理外存和系统级资源
  - 进程调度:管理CPU资源
  - 共同管理内存资源

6.3 用户接口

用户接口是用户与操作系统交互的界面,是用户使用计算机的桥梁。操作系统提供多种类型的用户接口,满足不同用户的需求。

6.3.1 命令接口

命令接口(Command Interface)是用户通过输入命令与操作系统交互的接口,也称为命令行接口(CLI,Command Line Interface)。

命令接口:

定义:
  - 用户通过输入命令与系统交互
  - 系统执行命令并返回结果
  - 文本形式的交互

特点:
  - 文本输入输出
  - 命令驱动
  - 精确控制
  - 适合熟练用户

类型:
  1. 联机命令接口(交互式)
  2. 脱机命令接口(批处理)

1. 联机命令接口(交互式命令接口)

联机命令接口是用户通过终端输入命令,系统立即执行并返回结果的接口。

联机命令接口:

特点:
  - 用户输入命令
  - 系统立即执行
  - 立即返回结果
  - 交互式操作

工作过程:
  1. 系统显示提示符
  2. 用户输入命令
  3. 系统解析命令
  4. 执行命令
  5. 显示结果
  6. 返回提示符

例子(Linux):
  $ ls -l
  total 24
  -rw-r--r-- 1 user user 1024 Jan 1 10:00 file1.txt
  -rw-r--r-- 1 user user 2048 Jan 1 10:01 file2.txt
  drwxr-xr-x 2 user user 4096 Jan 1 10:02 dir1
  $

  过程:
    1. 系统显示提示符 $
    2. 用户输入 ls -l
    3. 系统执行列出文件命令
    4. 显示文件列表
    5. 返回提示符

命令的类型

命令类型:

1. 系统访问命令:
   - login: 登录系统
   - logout: 退出系统
   - passwd: 修改密码

2. 文件操作命令:
   - ls: 列出文件
   - cat: 显示文件内容
   - cp: 复制文件
   - mv: 移动文件
   - rm: 删除文件
   - mkdir: 创建目录
   - rmdir: 删除目录

3. 目录操作命令:
   - cd: 改变目录
   - pwd: 显示当前目录
   - find: 查找文件

4. 进程管理命令:
   - ps: 显示进程
   - kill: 终止进程
   - jobs: 显示作业
   - bg/fg: 后台/前台作业

5. 系统信息命令:
   - date: 显示日期时间
   - who: 显示登录用户
   - df: 显示磁盘使用
   - top: 显示系统状态

6. 输入输出重定向:
   - >: 输出重定向
   - >>: 追加输出
   - <: 输入重定向
   - |: 管道

7. 命令组合:
   - ;: 顺序执行
   - &&: 逻辑与
   - ||: 逻辑或

命令的格式

命令格式:

基本格式:
  命令名 [选项] [参数]

例子:
  ls -l /home/user
  
  命令名:ls(列出文件)
  选项:-l(长格式显示)
  参数:/home/user(目录路径)

选项:
  - 短选项:-l, -a, -h
  - 长选项:--long, --all, --human-readable
  - 可以组合:-lah

参数:
  - 命令操作的对象
  - 文件、目录等
  - 可以有多个参数

2. 脱机命令接口(批处理命令接口)

脱机命令接口是用户将多个命令写入文件,系统批量执行的接口。

脱机命令接口:

定义:
  - 用户将命令写入脚本文件
  - 系统批量执行
  - 也称为批处理

特点:
  - 命令预先写好
  - 批量执行
  - 不需要交互
  - 适合重复任务

脚本文件:
  - 包含多个命令
  - 可以包含控制结构
  - 可以包含变量
  - 可以包含函数

例子(Shell脚本):
  #!/bin/bash
  # 批处理脚本示例
  
  echo "开始处理"
  ls -l
  cp file1.txt file2.txt
  echo "处理完成"

执行:
  $ bash script.sh
  或
  $ ./script.sh(如果可执行)

优势:
  - 可以重复执行
  - 可以自动化任务
  - 适合系统管理
  - 提高效率

命令接口的优缺点

命令接口优缺点:

优点:
  1. 精确控制:
     - 可以精确控制操作
     - 功能强大
     - 适合高级用户

  2. 效率高:
     - 熟练用户操作快
     - 可以批量操作
     - 可以脚本化

  3. 资源占用少:
     - 不需要图形界面
     - 资源占用少
     - 适合服务器

  4. 远程操作:
     - 可以通过网络操作
     - 适合远程管理
     - 灵活方便

缺点:
  1. 学习曲线陡:
     - 需要记忆命令
     - 需要学习语法
     - 不适合新手

  2. 容易出错:
     - 命令输入错误
     - 参数错误
     - 需要仔细

  3. 不够直观:
     - 文本界面
     - 不够直观
     - 需要想象

使用场景:
  - 系统管理员
  - 程序员
  - 服务器管理
  - 自动化脚本

6.3.2 程序接口

程序接口(Program Interface)是应用程序调用操作系统功能的接口,也称为应用程序接口(API,Application Programming Interface)。

程序接口:

定义:
  - 应用程序调用操作系统功能的接口
  - 通过系统调用实现
  - 程序与系统交互的桥梁

特点:
  - 面向程序员
  - 函数调用形式
  - 提供系统功能
  - 隐藏系统细节

作用:
  1. 提供系统功能:
     - 文件操作
     - 进程管理
     - 内存管理
     - 设备管理

  2. 隐藏系统细节:
     - 封装系统实现
     - 简化编程
     - 提高可移植性

  3. 保护系统:
     - 通过接口访问
     - 控制访问权限
     - 保护系统安全

程序接口的类型

程序接口类型:

1. 系统调用(System Call):
   - 直接调用操作系统功能
   - 底层接口
   - 需要切换到内核态

2. 库函数(Library Function):
   - 封装系统调用
   - 提供高级功能
   - 在用户态执行

3. API(Application Programming Interface):
   - 应用程序接口
   - 可以是系统调用或库函数
   - 提供统一接口

关系:
  应用程序 → 库函数 → 系统调用 → 操作系统

系统调用示例

系统调用示例:

文件操作:
  int open(const char *pathname, int flags);
  ssize_t read(int fd, void *buf, size_t count);
  ssize_t write(int fd, const void *buf, size_t count);
  int close(int fd);

进程管理:
  pid_t fork(void);
  int execve(const char *pathname, char *const argv[]);
  pid_t wait(int *wstatus);
  int kill(pid_t pid, int sig);

内存管理:
  void *malloc(size_t size);
  void free(void *ptr);
  void *mmap(void *addr, size_t length, int prot, int flags);

网络通信:
  int socket(int domain, int type, int protocol);
  int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

程序接口的使用

程序接口使用示例:

C语言示例:
  #include <stdio.h>
  #include <fcntl.h>
  #include <unistd.h>
  
  int main() {
      // 打开文件(系统调用)
      int fd = open("file.txt", O_RDONLY);
      
      if (fd < 0) {
          perror("open failed");
          return 1;
      }
      
      // 读取文件(系统调用)
      char buf[100];
      ssize_t n = read(fd, buf, sizeof(buf));
      
      // 写入标准输出(库函数,内部调用系统调用)
      printf("Read %zd bytes: %s\n", n, buf);
      
      // 关闭文件(系统调用)
      close(fd);
      
      return 0;
  }

说明:
  - open, read, close是系统调用
  - printf是库函数(内部调用write系统调用)
  - 程序通过接口使用系统功能

6.3.3 图形用户接口

图形用户接口(GUI,Graphical User Interface)是用户通过图形界面与操作系统交互的接口。

图形用户接口:

定义:
  - 使用图形元素与用户交互
  - 窗口、图标、菜单等
  - 鼠标点击操作

特点:
  - 直观易用
  - 图形化界面
  - 鼠标操作
  - 适合普通用户

组成元素:
  1. 窗口(Window)
  2. 图标(Icon)
  3. 菜单(Menu)
  4. 按钮(Button)
  5. 对话框(Dialog)
  6. 工具栏(Toolbar)

GUI的组成

GUI组成:

1. 窗口系统:
   - 管理窗口
   - 窗口创建、移动、关闭
   - 窗口重叠、切换

2. 图形库:
   - 绘制图形元素
   - 处理图形输出
   - 提供图形API

3. 输入处理:
   - 鼠标输入
   - 键盘输入
   - 触摸输入(移动设备)

4. 事件处理:
   - 处理用户事件
   - 鼠标点击、键盘输入
   - 窗口事件

5. 应用程序框架:
   - 提供应用程序框架
   - 简化GUI程序开发
   - 例如:Qt, GTK, Win32 API

GUI的工作过程

GUI工作过程:

1. 用户操作:
   - 鼠标点击按钮
   - 键盘输入文字
   - 窗口操作

2. 事件产生:
   - 系统捕获用户操作
   - 产生相应事件
   - 例如:鼠标点击事件

3. 事件分发:
   - 系统将事件分发给应用程序
   - 应用程序处理事件
   - 执行相应操作

4. 界面更新:
   - 应用程序更新界面
   - 显示结果
   - 反馈给用户

例子:
  用户点击"保存"按钮:
    1. 鼠标点击事件
    2. 系统捕获事件
    3. 分发给应用程序
    4. 应用程序执行保存操作
    5. 更新界面显示"已保存"

GUI的优缺点

GUI优缺点:

优点:
  1. 直观易用:
     - 图形界面直观
     - 不需要记忆命令
     - 适合普通用户

  2. 操作简单:
     - 鼠标点击操作
     - 拖放操作
     - 操作简单

  3. 信息丰富:
     - 可以显示丰富信息
     - 图形、图像、动画
     - 信息表达清晰

  4. 错误提示友好:
     - 图形化错误提示
     - 帮助信息
     - 用户友好

缺点:
  1. 资源占用多:
     - 需要图形系统
     - 占用内存和CPU
     - 资源消耗大

  2. 操作效率可能低:
     - 某些操作不如命令行快
     - 需要多次点击
     - 熟练用户可能觉得慢

  3. 远程操作不便:
     - 需要图形传输
     - 网络带宽要求高
     - 延迟可能较大

使用场景:
  - 桌面系统
  - 普通用户
  - 图形应用
  - 现代操作系统主要接口

现代GUI系统

现代GUI系统:

桌面系统:
  1. Windows:
     - Windows GUI
     - Win32 API
     - 现代Windows使用WPF/UWP

  2. macOS:
     - Aqua界面
     - Cocoa框架
     - 美观易用

  3. Linux:
     - X Window System
     - GNOME, KDE等桌面环境
     - 多种选择

移动系统:
  1. Android:
     - Material Design
     - 触摸优化
     - 适合移动设备

  2. iOS:
     - iOS界面
     - 触摸优化
     - 简洁美观

Web界面:
  - 浏览器作为GUI
  - HTML/CSS/JavaScript
  - 跨平台

用户接口的选择

用户接口选择:

接口类型      适用用户        适用场景        特点
─────────────────────────────────────────────
命令接口      系统管理员      服务器管理      精确、高效
程序接口      程序员          应用程序开发    功能强大
图形接口      普通用户        桌面应用        直观、易用

现代系统:
  - 通常提供多种接口
  - 用户可以根据需要选择
  - 不同接口适合不同场景
  - 相互补充

6.4 系统调用

系统调用(System Call)是操作系统提供给应用程序的接口,是应用程序请求操作系统服务的唯一方式。系统调用是用户态程序进入内核态的桥梁,是操作系统功能的核心接口。

6.4.1 系统调用的概念

系统调用的定义

系统调用是操作系统内核提供的函数,允许用户态程序请求内核服务。

系统调用:

定义:
  - 操作系统内核提供的函数
  - 用户态程序调用内核功能
  - 应用程序与操作系统交互的接口

特点:
  1. 特权操作:
     - 需要内核权限
     - 用户态程序不能直接执行
     - 必须通过系统调用

  2. 接口统一:
     - 提供统一的接口
     - 隐藏内核实现细节
     - 简化应用程序开发

  3. 安全保护:
     - 内核检查权限
     - 防止非法操作
     - 保护系统安全

  4. 状态切换:
     - 从用户态切换到内核态
     - 执行内核代码
     - 返回用户态

形象比喻:

如果把操作系统比作一个政府机构:

  • 应用程序 = 普通市民(用户态)
  • 操作系统内核 = 政府机构(内核态)
  • 系统调用 = 办事窗口(系统调用接口)
  • 办事流程 = 市民不能直接进入政府,必须通过窗口申请服务

市民(应用程序)通过窗口(系统调用)申请服务,政府(内核)处理请求并返回结果。

为什么需要系统调用

为什么需要系统调用:

1. 保护系统:
   - 用户程序不能直接访问硬件
   - 不能直接修改系统数据
   - 必须通过系统调用
   - 内核检查权限

2. 统一接口:
   - 提供统一的接口
   - 隐藏硬件差异
   - 简化编程
   - 提高可移植性

3. 资源管理:
   - 内核统一管理资源
   - 防止资源冲突
   - 公平分配资源
   - 提高系统效率

4. 抽象硬件:
   - 隐藏硬件细节
   - 提供高级抽象
   - 简化应用程序
   - 便于开发

系统调用的分类

系统调用分类:

1. 进程控制:
   - fork, exec, exit
   - wait, kill
   - 进程创建、终止、控制

2. 文件操作:
   - open, read, write, close
   - create, delete, link
   - 文件创建、读写、删除

3. 设备管理:
   - ioctl, read, write
   - 设备控制、读写

4. 信息维护:
   - getpid, gettime
   - 获取系统信息

5. 通信:
   - pipe, shmget
   - 进程间通信

6. 存储管理:
   - brk, mmap
   - 内存分配、映射

6.4.2 系统调用的类型

系统调用可以按功能分为多个类型,每类提供相关的系统功能。

1. 进程控制类系统调用

进程控制类系统调用:

1. fork():
   - 创建子进程
   - 返回子进程PID(父进程)或0(子进程)
   - Unix/Linux使用

2. exec()系列:
   - 执行新程序
   - 替换当前进程映像
   - execve, execl等

3. exit():
   - 终止进程
   - 返回退出码
   - 释放资源

4. wait() / waitpid():
   - 等待子进程终止
   - 获取子进程退出状态
   - 清理僵尸进程

5. kill():
   - 向进程发送信号
   - 可以终止进程
   - 进程间通信

例子:
  pid_t pid = fork();
  if (pid == 0) {
      // 子进程
      execve("/bin/ls", argv, envp);
  } else {
      // 父进程
      wait(&status);
  }

2. 文件操作类系统调用

文件操作类系统调用:

1. open():
   - 打开文件
   - 返回文件描述符
   - 指定打开方式

2. read():
   - 从文件读取数据
   - 返回读取的字节数
   - 可能阻塞

3. write():
   - 向文件写入数据
   - 返回写入的字节数
   - 可能阻塞

4. close():
   - 关闭文件
   - 释放文件描述符
   - 刷新缓冲区

5. lseek():
   - 改变文件指针位置
   - 支持随机访问
   - 返回新位置

6. stat() / fstat():
   - 获取文件属性
   - 文件大小、权限等
   - 文件元数据

例子:
  int fd = open("file.txt", O_RDONLY);
  char buf[100];
  ssize_t n = read(fd, buf, sizeof(buf));
  close(fd);

3. 设备管理类系统调用

设备管理类系统调用:

1. ioctl():
   - 设备控制
   - 设备特定操作
   - 灵活但复杂

2. read() / write():
   - 设备读写
   - 统一接口
   - 设备抽象为文件

例子:
  // 设置串口波特率
  ioctl(fd, TIOCSBRK, &baudrate);
  
  // 读取设备数据
  read(device_fd, buf, size);

4. 信息维护类系统调用

信息维护类系统调用:

1. getpid():
   - 获取进程ID
   - 当前进程标识

2. getuid() / getgid():
   - 获取用户ID
   - 获取组ID

3. time():
   - 获取系统时间
   - 时间戳

4. sysinfo():
   - 获取系统信息
   - 系统状态

例子:
  pid_t pid = getpid();
  uid_t uid = getuid();
  time_t now = time(NULL);

5. 通信类系统调用

通信类系统调用:

1. pipe():
   - 创建管道
   - 进程间通信
   - 单向通信

2. shmget() / shmat():
   - 共享内存
   - 创建和连接
   - 高效通信

3. msgget() / msgsnd() / msgrcv():
   - 消息队列
   - 发送和接收消息
   - 进程间通信

4. socket():
   - 创建套接字
   - 网络通信
   - 本地和网络

例子:
  int pipefd[2];
  pipe(pipefd);
  // pipefd[0]读端,pipefd[1]写端

6. 存储管理类系统调用

存储管理类系统调用:

1. brk() / sbrk():
   - 改变数据段大小
   - 内存分配
   - 底层内存管理

2. mmap() / munmap():
   - 内存映射
   - 文件映射到内存
   - 共享内存

3. mlock() / munlock():
   - 锁定内存
   - 防止换出
   - 实时应用

例子:
  void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE,
                    MAP_SHARED, fd, 0);
  // 将文件映射到内存

6.4.3 系统调用的实现

系统调用的实现涉及用户态到内核态的切换,是操作系统的核心机制。

系统调用的实现机制

系统调用实现机制:

1. 系统调用号:
   - 每个系统调用有唯一编号
   - 系统调用表索引
   - 例如:open=2, read=0, write=1

2. 系统调用表:
   - 内核中的函数指针数组
   - 索引是系统调用号
   - 值是处理函数地址

3. 调用过程:
   a. 用户程序设置系统调用号和参数
   b. 执行特殊指令(如int 0x80, syscall)
   c. CPU切换到内核态
   d. 内核查找系统调用表
   e. 调用对应的处理函数
   f. 执行系统调用
   g. 返回用户态
   h. 返回结果给用户程序

系统调用的调用过程

系统调用调用过程:

详细步骤:

1. 用户程序准备:
   - 设置系统调用号(寄存器)
   - 设置参数(寄存器或栈)
   - 执行系统调用指令

2. 硬件处理:
   - CPU检测到系统调用指令
   - 保存用户态上下文
   - 切换到内核态
   - 跳转到系统调用处理程序

3. 内核处理:
   - 系统调用处理程序运行
   - 从寄存器读取系统调用号
   - 查找系统调用表
   - 调用对应的处理函数

4. 执行系统调用:
   - 执行实际的系统调用函数
   - 检查参数合法性
   - 检查权限
   - 执行操作

5. 返回结果:
   - 将结果放入寄存器
   - 恢复用户态上下文
   - 返回到用户程序
   - 用户程序获得结果

时间线:
  用户态 → 系统调用指令 → 内核态 → 
  系统调用处理 → 返回 → 用户态

系统调用表

系统调用表:

结构:
  sys_call_table[] = {
      [0] = sys_read,      // read系统调用
      [1] = sys_write,     // write系统调用
      [2] = sys_open,       // open系统调用
      [3] = sys_close,     // close系统调用
      ...
  };

查找过程:
  系统调用号 = 2(open)
  → sys_call_table[2]
  → sys_open函数
  → 执行open系统调用

实现:
  - 系统调用表在内核中
  - 系统启动时初始化
  - 不同架构可能不同

系统调用的参数传递

系统调用参数传递:

方法:
  1. 寄存器传递:
     - 参数放在寄存器中
     - 速度快
     - 但寄存器数量有限

  2. 栈传递:
     - 参数放在栈中
     - 可以传递多个参数
     - 但速度稍慢

  3. 混合方式:
     - 前几个参数用寄存器
     - 其余参数用栈
     - 平衡性能和灵活性

例子(x86-64):
  open系统调用:
    - 系统调用号:放在rax寄存器
    - 参数1(路径):放在rdi寄存器
    - 参数2(标志):放在rsi寄存器
    - 参数3(权限):放在rdx寄存器
    - 执行syscall指令

系统调用的开销

系统调用开销:

开销来源:
  1. 状态切换:
     - 用户态→内核态切换
     - 保存和恢复上下文
     - 有一定开销

  2. 参数检查:
     - 检查参数合法性
     - 检查权限
     - 安全检查

  3. 内核执行:
     - 执行内核代码
     - 可能涉及复杂操作
     - 可能阻塞

优化方法:
  1. 减少系统调用次数:
     - 批量操作
     - 缓存结果
     - 减少切换

  2. 快速系统调用:
     - 使用专门的指令(如syscall)
     - 减少切换开销
     - 提高性能

  3. 系统调用合并:
     - 合并多个系统调用
     - 减少切换次数
     - 提高效率

典型开销:
  - 系统调用本身:1-10微秒
  - 加上实际操作:可能更长
  - 现代系统已优化

6.4.4 系统调用与库函数的关系

系统调用和库函数是不同层次的接口,它们有密切的关系但也有区别。

系统调用 vs 库函数:

系统调用:
  - 操作系统内核提供的接口
  - 直接调用内核功能
  - 需要切换到内核态
  - 底层接口

库函数:
  - 库提供的函数
  - 可能在用户态执行
  - 可能封装系统调用
  - 高级接口

关系:
  库函数可能:
  1. 直接调用系统调用
  2. 封装多个系统调用
  3. 完全在用户态实现
  4. 组合系统调用和用户态代码

库函数与系统调用的关系

库函数与系统调用的关系:

1. 直接封装系统调用:
   - 库函数直接调用系统调用
   - 提供更友好的接口
   - 例如:fopen() → open()

2. 封装多个系统调用:
   - 一个库函数调用多个系统调用
   - 提供高级功能
   - 例如:fprintf() → 多个write()

3. 完全用户态实现:
   - 库函数在用户态实现
   - 不调用系统调用
   - 例如:strlen(), strcpy()

4. 混合实现:
   - 部分用户态,部分系统调用
   - 优化性能
   - 例如:malloc() → brk() + 用户态管理

例子分析

例子分析:

1. printf():
   库函数:printf()
     ↓
   内部调用:write()系统调用
     ↓
   内核:sys_write()
   
   printf()是库函数
   内部调用write()系统调用

2. fopen():
   库函数:fopen()
     ↓
   内部调用:open()系统调用
     ↓
   创建FILE结构
     ↓
   返回FILE指针
   
   fopen()封装open()
   提供更高级的接口

3. malloc():
   库函数:malloc()
     ↓
   用户态内存管理
     ↓
   需要时调用:brk()或mmap()
     ↓
   内核:分配内存
   
   malloc()主要用户态实现
   需要时调用系统调用

4. strlen():
   库函数:strlen()
     ↓
   完全用户态实现
     ↓
   不调用系统调用
   
   纯用户态函数
   不需要系统调用

系统调用与库函数的对比

系统调用 vs 库函数对比:

特性          系统调用        库函数
─────────────────────────────────────
提供者        操作系统内核     库
执行位置      内核态          用户态(通常)
调用方式      特殊指令        普通函数调用
开销          较大            较小
功能          底层功能        高级功能
可移植性      系统相关        可能可移植
数量          较少(几百个)   很多(数千个)

选择:
  - 需要系统功能:使用系统调用
  - 需要高级功能:使用库函数
  - 通常使用库函数(更友好)
  - 库函数内部调用系统调用

系统调用的封装层次

系统调用封装层次:

应用程序
  ↓
库函数(高级接口)
  ↓
系统调用(底层接口)
  ↓
操作系统内核

例子:
  应用程序:printf("Hello")
    ↓
  库函数:fprintf(stdout, "Hello")
    ↓
  系统调用:write(1, "Hello", 5)
    ↓
  内核:sys_write()
    ↓
  设备驱动:输出到终端

层次:
  - 应用程序使用库函数(简单)
  - 库函数调用系统调用(封装)
  - 系统调用进入内核(底层)
  - 内核执行操作(实际工作)

现代系统的系统调用

现代系统系统调用:

Linux:
  - 系统调用号:0-400+
  - 使用syscall指令(x86-64)
  - 系统调用表:sys_call_table
  - 文档:man 2 syscalls

Windows:
  - 系统调用:通过ntdll.dll
  - API:Win32 API(库函数)
  - 应用程序通常使用Win32 API
  - 很少直接调用系统调用

macOS:
  - 系统调用:BSD系统调用
  - API:Cocoa框架
  - 应用程序使用高级API
  - 系统调用被封装

趋势:
  - 应用程序主要使用库函数
  - 系统调用被封装
  - 提供更高级的接口
  - 简化开发

系统调用总结

系统调用总结:

1. 系统调用是应用程序与操作系统交互的唯一方式:
   - 必须通过系统调用
   - 不能直接访问内核
   - 保护系统安全

2. 系统调用需要状态切换:
   - 用户态→内核态
   - 有一定开销
   - 需要优化

3. 库函数封装系统调用:
   - 提供更友好的接口
   - 简化编程
   - 提高可移植性

4. 现代系统:
   - 提供丰富的系统调用
   - 库函数封装系统调用
   - 应用程序主要使用库函数
   - 系统调用是底层基础

七、死锁

死锁是操作系统中的一个严重问题,指多个进程因竞争资源而相互等待,导致所有进程都无法继续执行。死锁会导致系统资源浪费,进程无法完成,是操作系统设计和实现中必须考虑和解决的问题。


7.1 死锁的基本概念

死锁是多个进程在竞争资源时出现的一种僵持状态,所有进程都在等待其他进程释放资源,但没有任何进程能够继续执行,导致系统无法正常工作。

7.1.1 死锁的定义

死锁的正式定义

死锁(Deadlock)是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

死锁的定义:

正式定义:
  - 一组进程处于死锁状态
  - 当且仅当这组进程中的每个进程
  - 都在等待该组中另一个进程占有的资源
  - 且这些资源不可抢占

关键特征:
  1. 多个进程参与
  2. 每个进程都在等待
  3. 等待的资源被其他进程占有
  4. 形成循环等待
  5. 无法自行解除

形象比喻:

如果把资源比作钥匙,进程比作需要钥匙的人:

  • 死锁 = 四个人,每人有一把钥匙,但需要另一把钥匙才能开门
  • 进程1 有钥匙A,需要钥匙B
  • 进程2 有钥匙B,需要钥匙C
  • 进程3 有钥匙C,需要钥匙D
  • 进程4 有钥匙D,需要钥匙A
  • 结果:所有人都在等待,但没有人能继续

死锁的典型例子

死锁典型例子:

哲学家就餐问题:
  5个哲学家围坐圆桌
  每人面前有一盘食物
  每两人之间有一根筷子
  需要两根筷子才能吃饭

死锁情况:
  所有哲学家同时拿起左边的筷子
  所有人都在等待右边的筷子
  但右边的筷子被其他人拿着
  所有人都在等待,无法继续
  形成死锁

资源:
  - 筷子(5根)
  - 进程:哲学家(5个)

等待关系:
  哲学家1等待哲学家2的筷子
  哲学家2等待哲学家3的筷子
  哲学家3等待哲学家4的筷子
  哲学家4等待哲学家5的筷子
  哲学家5等待哲学家1的筷子
  形成循环等待

死锁的图示表示

死锁图示:

资源分配图:
  进程    资源
  P1 ──→ R1(已分配)
  P2 ──→ R2(已分配)
  P1 ──→ R2(等待)
  P2 ──→ R1(等待)

  形成循环:
    P1 → R2 → P2 → R1 → P1
    循环等待,死锁!

资源分配图规则:
  - 进程 → 资源:进程请求资源
  - 资源 → 进程:资源分配给进程
  - 存在循环:可能死锁
  - 无循环:无死锁

7.1.2 产生死锁的原因

死锁的产生需要特定的条件,主要原因包括资源竞争和进程推进顺序不当。

产生死锁的原因:

1. 竞争不可抢占资源:
   - 多个进程竞争不可抢占资源
   - 资源被占用后不能强制释放
   - 例如:打印机、磁带机

2. 竞争可消耗资源:
   - 多个进程竞争可消耗资源
   - 资源使用后消失
   - 例如:消息、信号

3. 进程推进顺序不当:
   - 进程请求资源的顺序不当
   - 可能导致循环等待
   - 例如:都先请求资源A再请求资源B

4. 系统资源不足:
   - 系统资源有限
   - 无法满足所有进程需求
   - 导致竞争和等待

1. 竞争不可抢占资源

竞争不可抢占资源:

不可抢占资源:
  - 资源一旦分配,不能强制收回
  - 必须等待进程主动释放
  - 例如:打印机、磁带机、文件锁

死锁场景:
  进程P1:已占用打印机,需要磁带机
  进程P2:已占用磁带机,需要打印机

  情况:
    P1等待P2释放磁带机
    P2等待P1释放打印机
    两者互相等待,死锁!

例子:
  进程1:
    1. 申请打印机(获得)
    2. 申请磁带机(等待)
  
  进程2:
    1. 申请磁带机(获得)
    2. 申请打印机(等待)
  
  结果:两个进程都在等待,死锁

2. 竞争可消耗资源

竞争可消耗资源:

可消耗资源:
  - 资源使用后消失
  - 可以产生新的资源
  - 例如:消息、信号、中断

死锁场景:
  进程P1:等待进程P2发送消息
  进程P2:等待进程P3发送消息
  进程P3:等待进程P1发送消息

  情况:
    所有进程都在等待消息
    但没有人发送消息
    形成死锁

例子:
  进程1:receive(P2)  // 等待P2的消息
  进程2:receive(P3)  // 等待P3的消息
  进程3:receive(P1)  // 等待P1的消息
  
  结果:所有进程都在等待,死锁

3. 进程推进顺序不当

进程推进顺序不当:

问题:
  - 进程请求资源的顺序不当
  - 可能导致循环等待
  - 例如:都按相同顺序请求资源

死锁场景:
  所有进程都按相同顺序请求资源:
    先请求资源A
    再请求资源B
  
  如果进程1占用A,请求B
  进程2占用B,请求A
  就会死锁

例子:
  进程1:
    1. 请求资源A(获得)
    2. 请求资源B(等待)
  
  进程2:
    1. 请求资源B(获得)
    2. 请求资源A(等待)
  
  结果:死锁

如果顺序不同:
  进程1:先A后B
  进程2:先B后A
  可能死锁
  
  如果顺序相同:
  进程1:先A后B
  进程2:先A后B
  不会死锁(进程2等待进程1释放A)

4. 系统资源不足

系统资源不足:

问题:
  - 系统资源有限
  - 无法满足所有进程需求
  - 导致竞争和等待

死锁场景:
  系统有2个资源
  3个进程都需要2个资源
  
  情况:
    进程1占用2个资源
    进程2和进程3各等待2个资源
    但只有进程1释放资源后才有资源
    如果进程1也在等待其他资源,可能死锁

例子:
  系统:2个内存块
  进程1:需要2个,已获得2个
  进程2:需要2个,等待中
  进程3:需要2个,等待中
  
  如果进程1也在等待其他资源(如I/O)
  且进程2、进程3也在等待
  可能形成死锁

7.1.3 产生死锁的必要条件

死锁的产生需要同时满足四个必要条件,缺一不可。这四个条件是死锁的理论基础。

产生死锁的必要条件:

1. 互斥条件(Mutual Exclusion)
2. 请求和保持条件(Hold and Wait)
3. 不可抢占条件(No Preemption)
4. 循环等待条件(Circular Wait)

关系:
  - 四个条件同时满足 → 可能死锁
  - 只要破坏一个条件 → 不会死锁
  - 这是死锁预防的理论基础

1. 互斥条件(Mutual Exclusion)

互斥条件:

定义:
  - 资源不能被多个进程同时使用
  - 同一时刻只能被一个进程使用
  - 资源具有排他性

说明:
  - 如果资源可以共享,不会死锁
  - 但某些资源必须互斥使用
  - 例如:打印机、写文件

例子:
  打印机:
    - 不能同时被多个进程使用
    - 必须互斥访问
    - 满足互斥条件

  如果打印机可以共享:
    - 多个进程可以同时打印
    - 不会因为打印机死锁
    - 但实际不可能(打印会混乱)

破坏方法:
  - 使用SPOOLing技术
  - 将独占设备虚拟为共享设备
  - 避免互斥条件

2. 请求和保持条件(Hold and Wait)

请求和保持条件:

定义:
  - 进程已经占有一些资源
  - 同时请求新的资源
  - 在等待新资源时不释放已有资源

说明:
  - 进程保持已有资源
  - 同时请求新资源
  - 如果新资源不可用,继续等待

例子:
  进程P1:
    - 已占用资源A
    - 请求资源B(等待)
    - 不释放资源A
  
  进程P2:
    - 已占用资源B
    - 请求资源A(等待)
    - 不释放资源B
  
  结果:互相等待,死锁

破坏方法:
  - 进程必须一次性申请所有资源
  - 或者申请新资源前释放已有资源
  - 避免保持和等待同时发生

3. 不可抢占条件(No Preemption)

不可抢占条件:

定义:
  - 进程已获得的资源不能被强制抢占
  - 只能由进程主动释放
  - 其他进程不能强制收回

说明:
  - 资源一旦分配,不能强制收回
  - 必须等待进程主动释放
  - 如果资源可抢占,不会死锁

例子:
  进程P1占用打印机
  进程P2需要打印机
  
  如果不可抢占:
    - P2必须等待P1释放
    - 如果P1也在等待其他资源
    - 可能死锁
  
  如果可以抢占:
    - 系统可以强制收回打印机
    - 分配给P2
    - 不会死锁

破坏方法:
  - 允许系统强制收回资源
  - 资源可抢占
  - 但可能影响进程执行

4. 循环等待条件(Circular Wait)

循环等待条件:

定义:
  - 存在一个进程等待链
  - 链中每个进程等待下一个进程占有的资源
  - 最后一个进程等待第一个进程
  - 形成循环

说明:
  - 进程等待关系形成环
  - P1等待P2,P2等待P3,...,Pn等待P1
  - 形成循环等待

例子:
  进程P1:占用R1,等待R2
  进程P2:占用R2,等待R3
  进程P3:占用R3,等待R1
  
  等待链:
    P1 → R2 → P2 → R3 → P3 → R1 → P1
    形成循环,死锁!

破坏方法:
  - 对资源编号
  - 进程按编号顺序申请资源
  - 避免循环等待

四个条件的关系

四个条件的关系:

必要条件:
  - 四个条件都是必要条件
  - 必须同时满足才可能死锁
  - 破坏任何一个就不会死锁

充分性:
  - 四个条件同时满足 → 可能死锁
  - 但不一定必然死锁
  - 还取决于进程执行顺序

死锁预防:
  - 破坏互斥条件:使用SPOOLing
  - 破坏请求和保持:一次性分配
  - 破坏不可抢占:允许抢占
  - 破坏循环等待:资源有序分配

实际应用:
  - 通常破坏请求和保持或循环等待
  - 最容易实现
  - 效果最好

死锁的必要条件总结

死锁必要条件总结:

条件          含义                破坏方法
─────────────────────────────────────────
互斥条件      资源排他使用        SPOOLing
请求和保持    保持资源同时请求    一次性分配
不可抢占      资源不能强制收回    允许抢占
循环等待      等待关系形成环      资源有序分配

预防策略:
  - 破坏一个或多个条件
  - 防止死锁发生
  - 但可能影响系统性能
  - 需要权衡

7.2 死锁的处理方法

死锁的处理方法主要有四种:预防、避免、检测和解除。不同的方法有不同的特点和适用场景,系统可以根据需要选择合适的方法。

死锁处理方法:

1. 死锁预防(Deadlock Prevention):
   - 破坏死锁的必要条件
   - 防止死锁发生
   - 静态方法

2. 死锁避免(Deadlock Avoidance):
   - 动态检查资源分配
   - 避免进入不安全状态
   - 动态方法

3. 死锁检测(Deadlock Detection):
   - 允许死锁发生
   - 定期检测死锁
   - 发现后处理

4. 死锁解除(Deadlock Recovery):
   - 检测到死锁后解除
   - 恢复系统正常运行
   - 处理已发生的死锁

7.2.1 死锁的预防

死锁预防通过破坏死锁的四个必要条件之一,从根本上防止死锁的发生。

死锁预防策略:

1. 破坏互斥条件:
   - 使用SPOOLing技术
   - 将独占设备虚拟为共享设备
   - 但某些资源必须互斥

2. 破坏请求和保持条件:
   - 一次性分配所有资源
   - 或申请前释放已有资源
   - 最常用方法

3. 破坏不可抢占条件:
   - 允许系统抢占资源
   - 强制收回资源
   - 但实现复杂

4. 破坏循环等待条件:
   - 对资源编号
   - 按编号顺序申请
   - 常用方法

1. 破坏互斥条件

破坏互斥条件:

方法:
  - 使用SPOOLing技术
  - 将独占设备虚拟为共享设备
  - 避免互斥访问

例子(打印机):
  不使用SPOOLing:
    - 打印机是独占设备
    - 必须互斥访问
    - 可能死锁

  使用SPOOLing:
    - 打印机虚拟为共享设备
    - 多个进程可以"同时"使用
    - 避免互斥,不会死锁

限制:
  - 某些资源必须互斥
  - 例如:写文件、修改共享数据
  - 不能完全避免互斥

实际应用:
  - 主要用于打印机等设备
  - 不能解决所有死锁问题
  - 需要结合其他方法

2. 破坏请求和保持条件

破坏请求和保持条件:

方法1:一次性分配(Allocate All):
  - 进程必须一次性申请所有需要的资源
  - 如果资源不足,不分配任何资源
  - 等待所有资源都可用

  优点:
    - 简单有效
    - 不会死锁
    - 实现容易

  缺点:
    - 资源利用率低
    - 进程可能长时间等待
    - 可能饥饿

方法2:释放后申请(Release Before Request):
  - 申请新资源前释放已有资源
  - 然后重新申请所有资源
  - 避免保持和等待

  优点:
    - 不会死锁
    - 资源利用率较高

  缺点:
    - 可能丢失工作
    - 需要保存和恢复状态
    - 实现复杂

例子(一次性分配):
  进程需要:打印机、磁带机、内存
  
  不使用一次性分配:
    1. 申请打印机(获得)
    2. 申请磁带机(等待)
    3. 可能死锁
  
  使用一次性分配:
    1. 同时申请打印机、磁带机、内存
    2. 如果都可用,全部分配
    3. 如果不可用,都不分配,等待
    4. 不会死锁

3. 破坏不可抢占条件

破坏不可抢占条件:

方法:
  - 允许系统强制收回资源
  - 资源可以被抢占
  - 分配给其他进程

实现:
  1. 进程请求资源不可用时:
     - 检查占用该资源的进程
     - 如果该进程也在等待其他资源
     - 强制收回资源,分配给请求进程

  2. 被抢占的进程:
     - 保存当前状态
     - 释放被抢占的资源
     - 重新申请所有资源

优点:
  - 不会死锁
  - 资源利用率较高

缺点:
  1. 实现复杂:
     - 需要保存和恢复状态
     - 需要处理抢占
     - 实现困难

  2. 可能影响进程:
     - 进程执行被中断
     - 可能重复工作
     - 影响性能

使用场景:
  - CPU资源(可抢占)
  - 某些内存资源
  - 不适合所有资源

4. 破坏循环等待条件

破坏循环等待条件:

方法:
  - 对资源进行编号
  - 进程必须按编号顺序申请资源
  - 不能先申请编号大的再申请编号小的

规则:
  1. 资源编号:R1, R2, R3, ..., Rn
  2. 进程申请顺序:必须从小到大
  3. 不能违反顺序

例子:
  资源编号:
    R1: 打印机
    R2: 磁带机
    R3: 磁盘

  正确顺序:
    进程1:先R1,后R2 ✓
    进程2:先R1,后R3 ✓
    进程3:先R2,后R3 ✓

  错误顺序:
    进程1:先R2,后R1 ✗(违反顺序)

  为什么不会死锁:
    - 所有进程都按相同顺序申请
    - 不会形成循环等待
    - 例如:都先申请R1,只有一个能获得
    - 其他等待,不会循环

优点:
  1. 简单有效:
     - 实现简单
     - 效果明显
     - 不会死锁

  2. 资源利用率较高:
     - 不需要一次性分配
     - 可以逐步申请
     - 利用率较高

缺点:
  1. 资源编号困难:
     - 需要合理编号
     - 编号影响效率
     - 可能不直观

  2. 可能增加等待:
     - 必须按顺序申请
     - 可能增加等待时间
     - 但不会死锁

实际应用:
  - 最常用的预防方法
  - 简单有效
  - 广泛使用

死锁预防方法对比

死锁预防方法对比:

方法          效果    实现复杂度  资源利用率  实际使用
─────────────────────────────────────────────
破坏互斥      部分    简单        高          设备SPOOLing
破坏请求保持  好      中等        低          较少使用
破坏不可抢占  好      复杂        中          部分资源
破坏循环等待  好      简单        中高        最常用

选择:
  - 最常用:破坏循环等待
  - 简单有效
  - 资源利用率较高
  - 实现容易

7.2.2 死锁的避免

死锁避免不破坏死锁的必要条件,而是在资源分配时动态检查,避免系统进入可能导致死锁的状态。

死锁避免:

定义:
  - 在资源分配时动态检查
  - 判断分配后是否安全
  - 只有安全才分配
  - 避免进入不安全状态

特点:
  - 不破坏必要条件
  - 动态检查
  - 需要知道资源需求
  - 可能拒绝分配

与预防的区别:
  预防:
    - 破坏必要条件
    - 静态方法
    - 限制严格
  
  避免:
    - 不破坏条件
    - 动态检查
    - 更灵活

系统安全状态

系统安全状态是死锁避免的核心概念。

系统安全状态:

定义:
  - 系统存在一个安全序列
  - 按照该序列分配资源
  - 所有进程都能完成
  - 不会死锁

安全序列:
  - 进程执行序列:P1, P2, ..., Pn
  - 对每个进程Pi:
    * Pi需要的资源 <= 当前可用资源 + 前面进程释放的资源
    * Pi可以完成
    * Pi释放资源
  - 所有进程都能完成

安全状态 vs 不安全状态:
  安全状态:
    - 存在安全序列
    - 不会死锁
    - 可以继续分配资源
  
  不安全状态:
    - 不存在安全序列
    - 可能死锁
    - 不应该分配资源

注意:
  - 不安全状态不一定是死锁
  - 但可能导致死锁
  - 应该避免

安全状态示例

安全状态示例:

系统状态:
  资源总数:12
  可用资源:3
  进程:
    P1: 已分配5,最大需求10,还需要5
    P2: 已分配2,最大需求4,还需要2
    P3: 已分配2,最大需求9,还需要7

检查安全序列:
  序列1:P2 → P1 → P3
    P2需要2,可用3,可以完成
      完成后释放2,可用变为5
    P1需要5,可用5,可以完成
      完成后释放5,可用变为10
    P3需要7,可用10,可以完成
    安全序列存在,系统安全

  序列2:P1 → P2 → P3
    P1需要5,可用3,不能完成
    不是安全序列

结论:
  - 存在安全序列(P2 → P1 → P3)
  - 系统处于安全状态
  - 可以分配资源

银行家算法(Banker’s Algorithm)

银行家算法是死锁避免的经典算法,由Dijkstra提出。

银行家算法:

思想:
  - 银行家(系统)有有限资金(资源)
  - 客户(进程)申请贷款(资源)
  - 银行家检查贷款后是否安全
  - 只有安全才批准贷款

算法数据结构:
  1. Available[m]:
     - 可用资源向量
     - Available[i] = 资源i的可用数量

  2. Max[n][m]:
     - 最大需求矩阵
     - Max[i][j] = 进程i对资源j的最大需求

  3. Allocation[n][m]:
     - 分配矩阵
     - Allocation[i][j] = 进程i已分配资源j的数量

  4. Need[n][m]:
     - 需求矩阵
     - Need[i][j] = 进程i还需要资源j的数量
     - Need[i][j] = Max[i][j] - Allocation[i][j]

银行家算法的安全性检查

银行家算法安全性检查:

算法:
  1. 初始化:
     Work = Available
     Finish[i] = false (所有进程)

  2. 查找进程:
     找到进程i满足:
       Finish[i] = false
       Need[i] <= Work
     如果找到,继续步骤3
     如果找不到,转到步骤4

  3. 假设进程i完成:
     Work = Work + Allocation[i]
     Finish[i] = true
     转到步骤2

  4. 检查:
     如果所有Finish[i] = true
       系统安全
     否则
       系统不安全

例子:
  系统:3种资源,总数(10, 5, 7)
  可用:(3, 3, 2)
  
  进程:
    P0: Allocation(0,1,0), Need(7,4,3), Max(7,5,3)
    P1: Allocation(2,0,0), Need(1,2,2), Max(3,2,2)
    P2: Allocation(3,0,2), Need(6,0,0), Max(9,0,2)
    P3: Allocation(2,1,1), Need(0,1,1), Max(2,2,2)
    P4: Allocation(0,0,2), Need(4,3,1), Max(4,3,3)

  安全性检查:
    Work = (3,3,2)
    
    查找:P1的Need(1,2,2) <= Work(3,3,2) ✓
      Work = (3,3,2) + (2,0,0) = (5,3,2)
      Finish[1] = true
    
    查找:P3的Need(0,1,1) <= Work(5,3,2) ✓
      Work = (5,3,2) + (2,1,1) = (7,4,3)
      Finish[3] = true
    
    查找:P4的Need(4,3,1) <= Work(7,4,3) ✓
      Work = (7,4,3) + (0,0,2) = (7,4,5)
      Finish[4] = true
    
    查找:P0的Need(7,4,3) <= Work(7,4,5) ✓
      Work = (7,4,5) + (0,1,0) = (7,5,5)
      Finish[0] = true
    
    查找:P2的Need(6,0,0) <= Work(7,5,5) ✓
      Work = (7,5,5) + (3,0,2) = (10,5,7)
      Finish[2] = true
    
    所有Finish = true,系统安全
    安全序列:P1 → P3 → P4 → P0 → P2

银行家算法的资源分配

银行家算法资源分配:

当进程请求资源时:

1. 检查请求是否合法:
   Request[i] <= Need[i]
   Request[i] <= Available
   如果不合法,拒绝

2. 试探性分配:
   Available = Available - Request[i]
   Allocation[i] = Allocation[i] + Request[i]
   Need[i] = Need[i] - Request[i]

3. 安全性检查:
   调用安全性检查算法
   如果安全,正式分配
   如果不安全,恢复分配,拒绝请求

例子:
  进程P1请求资源(1,0,2)
  
  步骤1:检查合法性
    Request(1,0,2) <= Need[1](1,2,2) ✓
    Request(1,0,2) <= Available(3,3,2) ✓
    合法
  
  步骤2:试探性分配
    Available = (3,3,2) - (1,0,2) = (2,3,0)
    Allocation[1] = (2,0,0) + (1,0,2) = (3,0,2)
    Need[1] = (1,2,2) - (1,0,2) = (0,2,0)
  
  步骤3:安全性检查
    检查新状态是否安全
    如果安全,正式分配
    如果不安全,恢复,拒绝

银行家算法的优缺点

银行家算法优缺点:

优点:
  1. 避免死锁:
     - 动态检查
     - 避免不安全状态
     - 不会死锁

  2. 资源利用率较高:
     - 不限制资源申请顺序
     - 允许逐步申请
     - 利用率较高

  3. 灵活:
     - 动态适应
     - 不需要预先知道所有需求
     - 相对灵活

缺点:
  1. 需要知道最大需求:
     - 需要预先知道Max矩阵
     - 实际难以预测
     - 限制使用

  2. 进程数受限:
     - 算法复杂度O(m×n²)
     - 进程数多时计算量大
     - 性能影响

  3. 可能拒绝合法请求:
     - 即使资源足够
     - 如果会导致不安全状态
     - 也会拒绝

使用场景:
  - 理论重要
  - 实际系统较少使用
  - 主要用于教学和研究

7.2.3 死锁的检测

死锁检测允许死锁发生,但定期检测系统是否出现死锁,如果发现死锁则处理。

死锁检测:

策略:
  - 不预防死锁
  - 允许死锁发生
  - 定期检测死锁
  - 发现后处理

优点:
  - 不限制资源分配
  - 资源利用率高
  - 系统灵活性高

缺点:
  - 死锁可能发生
  - 需要检测和处理
  - 可能影响系统

检测时机:
  1. 定时检测:
     - 定期运行检测算法
     - 例如:每小时检测一次

  2. 资源请求时检测:
     - 每次资源请求时检测
     - 及时发现死锁

  3. CPU利用率低时检测:
     - CPU利用率低可能表示死锁
     - 此时检测

死锁检测算法

死锁检测算法通过资源分配图检测是否存在循环等待。

死锁检测算法:

数据结构:
  1. Available[m]:可用资源向量
  2. Allocation[n][m]:分配矩阵
  3. Request[n][m]:请求矩阵(进程当前请求)

算法:
  1. 初始化:
     Work = Available
     Finish[i] = false (如果Allocation[i] != 0)
     Finish[i] = true (如果Allocation[i] == 0)

  2. 查找进程:
     找到进程i满足:
       Finish[i] = false
       Request[i] <= Work
     如果找到,继续步骤3
     如果找不到,转到步骤4

  3. 假设进程i完成:
     Work = Work + Allocation[i]
     Finish[i] = true
     转到步骤2

  4. 检查:
     如果所有Finish[i] = true
       无死锁
     否则
       存在死锁
       Finish[i] = false的进程是死锁进程

原理:
  - 模拟资源分配
  - 可以完成的进程标记为完成
  - 无法完成的进程可能是死锁进程

死锁检测示例

死锁检测示例:

系统状态:
  资源:A(7个), B(2个), C(6个)
  可用:A(0), B(0), C(0)

  进程:
    P0: Allocation(0,1,0), Request(0,0,0)
    P1: Allocation(2,0,0), Request(2,0,2)
    P2: Allocation(3,0,3), Request(0,0,0)
    P3: Allocation(2,1,1), Request(1,0,0)
    P4: Allocation(0,0,2), Request(0,0,2)

检测过程:
  Work = (0,0,0)
  
  步骤1:初始化Finish
    P0: Allocation != 0, Finish = false
    P1: Allocation != 0, Finish = false
    P2: Allocation != 0, Finish = false
    P3: Allocation != 0, Finish = false
    P4: Allocation != 0, Finish = false
  
  步骤2:查找进程
    P0: Request(0,0,0) <= Work(0,0,0) ✓
      Work = (0,0,0) + (0,1,0) = (0,1,0)
      Finish[0] = true
    
    P2: Request(0,0,0) <= Work(0,1,0) ✓
      Work = (0,1,0) + (3,0,3) = (3,1,3)
      Finish[2] = true
    
    P3: Request(1,0,0) <= Work(3,1,3) ✓
      Work = (3,1,3) + (2,1,1) = (5,2,4)
      Finish[3] = true
    
    P1: Request(2,0,2) <= Work(5,2,4) ✓
      Work = (5,2,4) + (2,0,0) = (7,2,4)
      Finish[1] = true
    
    P4: Request(0,0,2) <= Work(7,2,4) ✓
      Work = (7,2,4) + (0,0,2) = (7,2,6)
      Finish[4] = true
  
  所有Finish = true,无死锁

死锁检测的复杂度

死锁检测复杂度:

时间复杂度:
  - O(m × n²)
  - m是资源类型数
  - n是进程数

优化:
  - 使用资源分配图
  - 检测图中是否有环
  - 可以使用DFS检测环
  - 复杂度可以降低

检测频率:
  - 频率高:及时发现,但开销大
  - 频率低:开销小,但可能延迟发现
  - 需要平衡

实际系统:
  - 通常定时检测
  - 或资源请求时检测
  - 根据系统负载调整

7.2.4 死锁的解除

死锁解除是在检测到死锁后,采取措施解除死锁,恢复系统正常运行。

死锁解除:

前提:
  - 已经检测到死锁
  - 需要解除死锁
  - 恢复系统运行

方法:
  1. 终止进程
  2. 抢占资源
  3. 回滚操作

1. 终止进程

终止进程是解除死锁最直接的方法。

终止进程:

方法:
  1. 终止所有死锁进程:
     - 简单直接
     - 但损失大
     - 所有工作丢失

  2. 逐个终止进程:
     - 终止一个进程
     - 检查是否解除死锁
     - 如果未解除,继续终止
     - 直到死锁解除

终止顺序选择:
  1. 优先级:
     - 终止优先级低的进程
     - 保留重要进程

  2. 执行时间:
     - 终止执行时间短的进程
     - 减少损失

  3. 资源占用:
     - 终止占用资源少的进程
     - 快速释放资源

  4. 完成度:
     - 终止完成度低的进程
     - 减少重复工作

例子:
  死锁进程:P1, P2, P3
  
  选择终止P2(优先级最低):
    1. 终止P2
    2. P2释放资源
    3. P1和P3获得资源
    4. 死锁解除
    5. P1和P3继续执行

2. 抢占资源

抢占资源是从死锁进程中强制收回资源,解除死锁。

抢占资源:

方法:
  1. 选择被抢占的进程:
     - 选择优先级低的进程
     - 或选择容易恢复的进程

  2. 强制收回资源:
     - 从选中进程收回资源
     - 分配给等待的进程

  3. 进程恢复:
     - 被抢占的进程回滚
     - 重新申请资源
     - 继续执行

选择被抢占进程的原则:
  1. 优先级:
     - 选择优先级低的进程
     - 保留重要进程

  2. 资源占用:
     - 选择占用资源少的进程
     - 快速释放资源

  3. 执行时间:
     - 选择执行时间短的进程
     - 减少回滚损失

  4. 回滚成本:
     - 选择回滚成本低的进程
     - 容易恢复

例子:
  死锁:P1等待P2的资源,P2等待P1的资源
  
  抢占P2的资源:
    1. 强制收回P2的资源
    2. 分配给P1
    3. P1继续执行
    4. P2回滚,重新申请资源
    5. 死锁解除

3. 回滚操作

回滚操作是将进程回滚到死锁发生前的状态。

回滚操作:

方法:
  1. 检查点(Checkpoint):
     - 定期保存进程状态
     - 记录检查点
     - 用于回滚

  2. 回滚到检查点:
     - 将进程状态恢复到检查点
     - 释放检查点后获得的资源
     - 重新执行

  3. 饥饿问题:
     - 可能同一进程反复被回滚
     - 需要防止饥饿
     - 记录回滚次数

检查点机制:
  - 系统定期创建检查点
  - 保存进程状态
  - 包括:寄存器、内存、文件状态等
  - 用于故障恢复和死锁解除

回滚成本:
  - 需要保存和恢复状态
  - 可能重复执行
  - 有性能开销
  - 需要权衡

死锁解除方法对比

死锁解除方法对比:

方法          效果    实现复杂度  损失    适用场景
─────────────────────────────────────────────
终止所有进程   好      简单        大      紧急情况
逐个终止进程   好      中等        中      常用
抢占资源       好      复杂        中      有检查点
回滚操作       好      复杂        小      有检查点系统

选择:
  - 通常使用逐个终止进程
  - 简单有效
  - 损失可接受
  - 实现相对简单

死锁处理方法总结

死锁处理方法总结:

方法          策略          优点          缺点          使用场景
─────────────────────────────────────────────────────
预防          破坏条件      不会死锁      限制严格      严格系统
避免          动态检查      灵活          需要预测      理论重要
检测和解除    允许发生      灵活          可能发生      实际系统常用

现代系统:
  - 主要使用检测和解除
  - 结合预防(资源有序分配)
  - 平衡性能和安全性
  - 实际系统常用组合方法

死锁处理的综合策略

死锁处理综合策略:

实际系统策略:
  1. 预防(部分):
     - 对某些资源使用有序分配
     - 避免明显的死锁

  2. 检测:
     - 定期检测死锁
     - 或资源请求时检测
     - 及时发现

  3. 解除:
     - 检测到死锁后解除
     - 终止部分进程
     - 恢复系统

组合优势:
  - 预防减少死锁概率
  - 检测及时发现
  - 解除恢复系统
  - 平衡各种因素

现代操作系统:
  - Linux:主要使用检测和解除
  - Windows:类似策略
  - 结合预防措施
  - 实际效果良好

八、操作系统安全

操作系统安全是操作系统设计和使用中的重要问题。随着计算机网络的普及和信息安全威胁的增加,操作系统安全变得越来越重要。操作系统需要提供安全机制来保护系统资源、用户数据和系统完整性。


8.1 操作系统安全概述

操作系统安全是指保护操作系统及其管理的资源免受未授权访问、恶意攻击和意外破坏。操作系统安全涉及多个方面,包括身份认证、访问控制、数据加密、审计等。

8.1.1 安全威胁

操作系统面临多种安全威胁,了解这些威胁是设计安全机制的基础。

安全威胁分类:

1. 未授权访问:
   - 非法用户访问系统
   - 未授权访问资源
   - 权限提升

2. 恶意软件:
   - 病毒、蠕虫、木马
   - 恶意代码执行
   - 系统破坏

3. 数据泄露:
   - 敏感数据泄露
   - 隐私信息泄露
   - 数据窃取

4. 拒绝服务:
   - 系统资源耗尽
   - 服务不可用
   - 系统崩溃

5. 完整性破坏:
   - 数据被篡改
   - 系统文件被修改
   - 配置被改变

1. 未授权访问

未授权访问:

定义:
  - 未经授权的用户或进程访问系统资源
  - 绕过访问控制机制
  - 获得不应有的权限

威胁类型:
  1. 非法登录:
     - 使用他人账户登录
     - 破解密码
     - 利用系统漏洞

  2. 权限提升:
     - 普通用户获得管理员权限
     - 利用系统漏洞
     - 执行特权操作

  3. 未授权资源访问:
     - 访问其他用户的文件
     - 访问系统文件
     - 访问受限资源

例子:
  - 密码破解:暴力破解用户密码
  - 缓冲区溢出:利用程序漏洞获得权限
  - 社会工程:欺骗用户获得密码
  - 后门程序:留下后门供以后访问

防护:
  - 强密码策略
  - 访问控制
  - 最小权限原则
  - 安全审计

2. 恶意软件

恶意软件:

定义:
  - 恶意设计的软件
  - 破坏系统或窃取信息
  - 未经用户同意安装

类型:
  1. 病毒(Virus):
     - 自我复制的恶意代码
     - 需要宿主程序
     - 传播和破坏

  2. 蠕虫(Worm):
     - 独立的恶意程序
     - 通过网络传播
     - 自我复制

  3. 木马(Trojan):
     - 伪装成正常程序
     - 执行恶意功能
     - 欺骗用户

  4. 间谍软件(Spyware):
     - 收集用户信息
     - 监控用户行为
     - 隐私侵犯

  5. 勒索软件(Ransomware):
     - 加密用户文件
     - 要求赎金
     - 数据勒索

威胁:
  - 系统破坏
  - 数据丢失
  - 隐私泄露
  - 资源消耗

防护:
  - 防病毒软件
  - 防火墙
  - 系统更新
  - 用户教育

3. 数据泄露

数据泄露:

定义:
  - 敏感数据被未授权访问
  - 数据被窃取或泄露
  - 隐私信息暴露

泄露途径:
  1. 网络攻击:
     - 网络监听
     - 中间人攻击
     - 数据包捕获

  2. 存储设备:
     - 硬盘丢失
     - 备份泄露
     - 设备丢弃

  3. 内部泄露:
     - 内部人员泄露
     - 权限滥用
     - 误操作

  4. 应用程序漏洞:
     - SQL注入
     - 跨站脚本
     - 应用程序缺陷

影响:
  - 隐私侵犯
  - 经济损失
  - 声誉损害
  - 法律责任

防护:
  - 数据加密
  - 访问控制
  - 数据备份
  - 安全传输

4. 拒绝服务攻击(DoS)

拒绝服务攻击:

定义:
  - 使系统或服务不可用
  - 耗尽系统资源
  - 阻止合法用户访问

类型:
  1. 资源耗尽:
     - CPU资源耗尽
     - 内存资源耗尽
     - 网络带宽耗尽
     - 磁盘空间耗尽

  2. 服务崩溃:
     - 利用漏洞使服务崩溃
     - 系统重启
     - 服务不可用

  3. 分布式拒绝服务(DDoS):
     - 多个攻击源同时攻击
     - 大规模攻击
     - 难以防御

例子:
  - 洪水攻击:发送大量数据包
  - 死亡之ping:发送超大ping包
  - SYN洪水:耗尽连接资源
  - 资源耗尽:创建大量进程

影响:
  - 服务不可用
  - 系统性能下降
  - 用户体验差
  - 经济损失

防护:
  - 流量限制
  - 防火墙
  - 入侵检测
  - 资源限制

5. 完整性破坏

完整性破坏:

定义:
  - 数据或系统被未授权修改
  - 文件被篡改
  - 配置被改变

威胁类型:
  1. 数据篡改:
     - 文件内容被修改
     - 数据库被篡改
     - 日志被删除

  2. 系统文件修改:
     - 系统文件被替换
     - 配置文件被修改
     - 可执行文件被感染

  3. 配置改变:
     - 安全配置被改变
     - 访问控制被修改
     - 系统设置被改变

影响:
  - 系统不可信
  - 数据不可靠
  - 安全机制失效
  - 系统不稳定

防护:
  - 文件完整性检查
  - 数字签名
  - 访问控制
  - 配置管理

8.1.2 安全机制

操作系统提供多种安全机制来应对安全威胁,保护系统安全。

安全机制:

1. 身份认证(Authentication)
2. 访问控制(Access Control)
3. 加密(Encryption)
4. 审计(Audit)
5. 防火墙(Firewall)
6. 入侵检测(Intrusion Detection)
7. 安全内核(Security Kernel)

1. 身份认证

身份认证:

定义:
  - 验证用户身份
  - 确认用户是谁
  - 防止未授权访问

认证方式:
  1. 密码认证:
     - 用户名和密码
     - 最常用方式
     - 需要强密码

  2. 生物特征认证:
     - 指纹识别
     - 面部识别
     - 虹膜识别

  3. 智能卡认证:
     - 物理卡片
     - 芯片存储密钥
     - 双因素认证

  4. 多因素认证:
     - 组合多种方式
     - 提高安全性
     - 例如:密码+短信验证码

实现:
  - 登录时验证
  - 会话管理
  - 定期重新认证
  - 安全存储凭证

2. 访问控制

访问控制:

定义:
  - 控制用户对资源的访问
  - 决定谁可以访问什么
  - 防止未授权访问

类型:
  1. 自主访问控制(DAC):
     - 资源所有者决定访问权限
     - 灵活但可能不安全

  2. 强制访问控制(MAC):
     - 系统强制实施访问规则
     - 安全但不够灵活

  3. 基于角色的访问控制(RBAC):
     - 基于角色分配权限
     - 平衡安全性和灵活性

实现:
  - 访问控制列表(ACL)
  - 权限位(Unix)
  - 安全标签(MAC)
  - 角色权限(RBAC)

3. 加密

加密:

定义:
  - 将数据转换为不可读形式
  - 只有授权用户可以解密
  - 保护数据机密性

类型:
  1. 对称加密:
     - 加密和解密使用相同密钥
     - 速度快
     - 密钥管理困难

  2. 非对称加密:
     - 加密和解密使用不同密钥
     - 密钥管理容易
     - 速度较慢

  3. 哈希函数:
     - 单向函数
     - 用于数据完整性
     - 密码存储

应用:
  - 数据加密存储
  - 网络传输加密
  - 密码存储
  - 数字签名

4. 审计

审计:

定义:
  - 记录系统活动
  - 追踪用户行为
  - 检测安全事件

审计内容:
  1. 登录和注销
  2. 文件访问
  3. 权限变更
  4. 系统配置修改
  5. 异常行为

审计日志:
  - 记录时间、用户、操作
  - 安全存储
  - 防止篡改
  - 定期分析

用途:
  - 安全事件调查
  - 合规性检查
  - 异常检测
  - 取证分析

5. 防火墙

防火墙:

定义:
  - 控制网络流量
  - 阻止未授权访问
  - 保护系统边界

类型:
  1. 包过滤防火墙:
     - 检查数据包
     - 根据规则过滤
     - 简单高效

  2. 状态检测防火墙:
     - 跟踪连接状态
     - 更智能的过滤
     - 性能较好

  3. 应用层防火墙:
     - 检查应用层数据
     - 深度包检测
     - 安全性高

功能:
  - 阻止未授权访问
  - 允许合法流量
  - 记录网络活动
  - 防止攻击

6. 入侵检测

入侵检测:

定义:
  - 检测系统入侵行为
  - 识别攻击模式
  - 及时响应

类型:
  1. 基于签名的检测:
     - 匹配已知攻击模式
     - 准确但只能检测已知攻击

  2. 基于异常的检测:
     - 检测异常行为
     - 可以发现未知攻击
     - 但可能误报

实现:
  - 实时监控
  - 日志分析
  - 模式匹配
  - 告警机制

8.1.3 安全模型

安全模型是描述系统安全策略的抽象框架,用于指导安全机制的设计和实现。

安全模型:

1. 访问矩阵模型
2. Bell-LaPadula模型
3. Biba模型
4. Clark-Wilson模型
5. 中国墙模型

1. 访问矩阵模型

访问矩阵模型:

定义:
  - 用矩阵表示访问权限
  - 行表示主体(用户、进程)
  - 列表示客体(文件、资源)
  - 矩阵元素表示权限

结构:
        文件1  文件2  文件3
  用户1  rw-    r--    ---
  用户2  r--    rw-    r--
  用户3  ---    ---    rwx

  权限:
    r: 读
    w: 写
    x: 执行
    -: 无权限

实现:
  - 访问控制列表(ACL):按列存储
  - 能力列表(Capability):按行存储
  - 简化实现:权限位(Unix)

特点:
  - 直观
  - 灵活
  - 但矩阵可能很大
  - 需要优化存储

2. Bell-LaPadula模型

Bell-LaPadula模型:

定义:
  - 多级安全模型
  - 用于军事和政府系统
  - 保护数据机密性

安全级别:
  - 公开(Unclassified)
  - 内部(Confidential)
  - 秘密(Secret)
  - 绝密(Top Secret)

规则:
  1. 简单安全属性(下读):
     - 主体只能读同级或更低级的客体
     - 不能向上读

  2. *-属性(上写):
     - 主体只能写同级或更高级的客体
     - 不能向下写

目的:
  - 防止信息泄露
  - 保护机密数据
  - 强制访问控制

例子:
  绝密用户:
    - 可以读:绝密、秘密、内部、公开
    - 可以写:绝密
    - 不能写:秘密、内部、公开(防止泄露)

  公开用户:
    - 可以读:公开
    - 可以写:公开
    - 不能读:内部、秘密、绝密

3. Biba模型

Biba模型:

定义:
  - 完整性模型
  - 保护数据完整性
  - 与Bell-LaPadula相对

完整性级别:
  - 高完整性
  - 中完整性
  - 低完整性

规则:
  1. 简单完整性属性(下写):
     - 主体只能写同级或更低级的客体
     - 不能向上写

  2. 完整性*属性(上读):
     - 主体只能读同级或更高级的客体
     - 不能向下读

目的:
  - 防止低完整性数据污染高完整性数据
  - 保护系统完整性
  - 防止恶意代码传播

例子:
  高完整性程序:
    - 可以读:高完整性数据
    - 可以写:高完整性、中完整性、低完整性
    - 不能读:低完整性数据(防止污染)

  低完整性程序:
    - 可以读:低完整性、中完整性、高完整性
    - 可以写:低完整性
    - 不能写:高完整性数据(防止污染)

4. Clark-Wilson模型

Clark-Wilson模型:

定义:
  - 商业完整性模型
  - 保护数据完整性
  - 适合商业应用

概念:
  1. 受约束数据项(CDI):
     - 需要保护的数据
     - 只能通过转换过程修改

  2. 不受约束数据项(UDI):
     - 不需要保护的数据
     - 可以自由修改

  3. 完整性验证过程(IVP):
     - 验证数据完整性
     - 检查数据是否正确

  4. 转换过程(TP):
     - 修改数据的唯一方式
     - 必须经过验证

规则:
  1. 所有转换过程必须经过认证
  2. 只有认证用户才能执行转换过程
  3. 必须维护审计日志
  4. 数据必须经过完整性验证

应用:
  - 数据库系统
  - 金融系统
  - 商业应用

5. 中国墙模型

中国墙模型:

定义:
  - 利益冲突模型
  - 防止利益冲突
  - 用于咨询、审计等行业

概念:
  1. 利益冲突类(COI):
     - 相互竞争的公司属于同一COI
     - 不能同时访问

  2. 公司数据集(CD):
     - 特定公司的数据
     - 属于某个COI

规则:
  1. 简单中国墙属性:
     - 用户访问一个CD后
     - 不能访问同一COI的其他CD

  2. 自主安全属性:
     - 用户可以访问任何CD
     - 只要不违反简单中国墙属性

目的:
  - 防止利益冲突
  - 保护客户隐私
  - 维护职业道德

例子:
  COI1:{公司A, 公司B}(竞争对手)
  COI2:{公司C, 公司D}(竞争对手)

  用户访问公司A的数据后:
    - 可以访问:公司C、公司D
    - 不能访问:公司B(同一COI)

安全模型对比

安全模型对比:

模型          目标        应用场景        特点
─────────────────────────────────────────
访问矩阵      通用        通用系统        灵活
Bell-LaPadula 机密性      军事政府        多级安全
Biba          完整性      系统保护        完整性保护
Clark-Wilson  完整性      商业应用        商业完整性
中国墙        利益冲突    咨询审计        冲突避免

选择:
  - 根据应用需求选择
  - 可以组合使用
  - 实际系统可能使用多种模型

8.2 访问控制

访问控制是操作系统安全的核心机制,决定谁可以访问什么资源,以及可以执行什么操作。访问控制是防止未授权访问的主要手段。

8.2.1 访问控制模型

访问控制模型定义了如何表示和控制访问权限。

访问控制模型:

基本概念:
  1. 主体(Subject):
     - 请求访问的实体
     - 用户、进程、程序
     - 主动访问者

  2. 客体(Object):
     - 被访问的资源
     - 文件、目录、设备
     - 被动被访问者

  3. 访问权限(Access Right):
     - 允许的操作
     - 读、写、执行等
     - 权限集合

访问控制三要素:
  - 主体(谁)
  - 客体(什么)
  - 权限(如何)

访问矩阵模型

访问矩阵模型:

定义:
  - 用矩阵表示所有访问权限
  - 行:主体
  - 列:客体
  - 元素:权限集合

矩阵示例:
        文件1    文件2    文件3    打印机
  用户1  {r,w}   {r}      {}       {}
  用户2  {r}     {r,w}    {r}      {}
  用户3  {}      {}       {r,w,x}  {w}
  进程1  {r}     {r}      {}       {}

实现方式:
  1. 访问控制列表(ACL):
     - 按列存储
     - 每个客体一个列表
     - 列出可以访问的主体和权限

  2. 能力列表(Capability):
     - 按行存储
     - 每个主体一个列表
     - 列出可以访问的客体和权限

  3. 权限位(Permission Bits):
     - 简化实现
     - Unix使用
     - 所有者、组、其他三类

8.2.2 自主访问控制(DAC)

自主访问控制(Discretionary Access Control,DAC)是最常用的访问控制方式,资源所有者决定访问权限。

自主访问控制(DAC):

定义:
  - 资源所有者自主决定访问权限
  - 可以授予或撤销权限
  - 灵活但可能不安全

特点:
  1. 自主性:
     - 所有者完全控制
     - 可以自由授权
     - 灵活性高

  2. 传递性:
     - 权限可以传递
     - 用户A授权给用户B
     - 用户B可以授权给用户C

  3. 可撤销:
     - 所有者可以撤销权限
     - 动态管理
     - 灵活控制

实现:
  - 访问控制列表(ACL)
  - 权限位(Unix)
  - 文件所有者控制

Unix权限位

Unix权限位:

结构:
  -rwxr-xr--
  所有者  组  其他

权限位:
  r: 读(4)
  w: 写(2)
  x: 执行(1)

权限值:
  rwx = 4+2+1 = 7
  r-x = 4+0+1 = 5
  r-- = 4+0+0 = 4

例子:
  -rwxr-xr-- 1 user group 1024 file.txt
  
  所有者(user):读写执行(rwx)
  组(group):读执行(r-x)
  其他:只读(r--)

权限设置:
  chmod 754 file.txt
  所有者:7(rwx)
  组:5(r-x)
  其他:4(r--)

目录权限:
  r: 列出目录内容
  w: 创建/删除文件
  x: 进入目录

访问控制列表(ACL)

访问控制列表(ACL):

定义:
  - 为每个客体维护访问列表
  - 列出可以访问的主体和权限
  - 比权限位更灵活

结构:
  文件:file.txt
  ACL:
    user1: rwx
    user2: r-x
    group1: r--
    others: ---

优势:
  - 可以为特定用户设置权限
  - 比权限位更细粒度
  - 更灵活

例子:
  文件:report.txt
  ACL:
    owner: rwx
    alice: rw-
    bob: r--
    group: r--
    others: ---

  说明:
    - 所有者:完全控制
    - alice:读写
    - bob:只读
    - 组:只读
    - 其他:无权限

DAC的优缺点

DAC优缺点:

优点:
  1. 灵活性高:
     - 所有者完全控制
     - 可以精细授权
     - 适应各种需求

  2. 实现简单:
     - 概念简单
     - 实现容易
     - 广泛使用

  3. 用户友好:
     - 用户容易理解
     - 操作简单
     - 适合个人系统

缺点:
  1. 安全性较低:
     - 所有者可能错误授权
     - 权限可能传递
     - 难以控制

  2. 管理困难:
     - 权限分散
     - 难以统一管理
     - 可能不一致

  3. 不适合高安全环境:
     - 不能强制安全策略
     - 用户可能绕过
     - 需要更高安全级别

使用场景:
  - 个人计算机
  - 一般服务器
  - 需要灵活性的系统
  - Unix/Linux系统

8.2.3 强制访问控制(MAC)

强制访问控制(Mandatory Access Control,MAC)由系统强制实施访问规则,用户不能改变。

强制访问控制(MAC):

定义:
  - 系统强制实施访问规则
  - 用户不能改变规则
  - 安全但不够灵活

特点:
  1. 强制性:
     - 系统强制实施
     - 用户不能绕过
     - 安全性高

  2. 不可改变:
     - 用户不能改变规则
     - 只能由管理员设置
     - 统一管理

  3. 多级安全:
     - 支持安全级别
     - 机密、秘密、绝密等
     - 防止信息泄露

实现:
  - 安全标签
  - 安全级别
  - 系统强制检查

安全标签

安全标签:

定义:
  - 为主体 and 客体分配安全标签
  - 标签包含安全级别
  - 系统根据标签决定访问

安全级别:
  - 公开(Unclassified)
  - 内部(Confidential)
  - 秘密(Secret)
  - 绝密(Top Secret)

标签结构:
  主体标签:
    - 用户:秘密级别
    - 可以访问:秘密及以下级别

  客体标签:
    - 文件:秘密级别
    - 只能被:秘密及以上级别访问

访问规则:
  1. 下读规则:
     - 主体只能读同级或更低级的客体
     - 防止信息泄露

  2. 上写规则:
     - 主体只能写同级或更高级的客体
     - 防止信息降级

例子:
  用户(秘密级别):
    - 可以读:公开、内部、秘密文件
    - 可以写:秘密、绝密文件
    - 不能读:绝密文件
    - 不能写:公开、内部文件

MAC的实现

MAC实现:

SELinux(Security-Enhanced Linux):
  - Linux的MAC实现
  - 使用安全上下文
  - 强制访问控制

安全上下文:
  用户:角色:类型:级别
  
  例子:
    user_u:object_r:file_t:s0
    system_u:system_r:httpd_t:s0

类型强制(TE):
  - 基于类型的访问控制
  - 定义类型和规则
  - 系统强制实施

规则示例:
  allow httpd_t file_t:file read;
  allow httpd_t file_t:file write;
  
  说明:
    - httpd_t类型可以读写file_t类型
    - 系统强制实施
    - 用户不能改变

MAC的优缺点

MAC优缺点:

优点:
  1. 安全性高:
     - 系统强制实施
     - 用户不能绕过
     - 适合高安全环境

  2. 统一管理:
     - 集中管理策略
     - 一致的安全策略
     - 便于维护

  3. 防止信息泄露:
     - 多级安全
     - 强制规则
     - 有效防护

缺点:
  1. 灵活性低:
     - 用户不能改变
     - 配置复杂
     - 可能影响使用

  2. 实现复杂:
     - 需要定义策略
     - 配置困难
     - 需要专业知识

  3. 性能影响:
     - 每次访问都检查
     - 可能影响性能
     - 需要优化

使用场景:
  - 军事系统
  - 政府系统
  - 高安全环境
  - 需要强制策略的系统

8.2.4 基于角色的访问控制(RBAC)

基于角色的访问控制(Role-Based Access Control,RBAC)通过角色来管理权限,是DAC和MAC的折中方案。

基于角色的访问控制(RBAC):

定义:
  - 用户被分配角色
  - 角色有权限
  - 用户通过角色获得权限

核心概念:
  1. 用户(User):
     - 系统的使用者
     - 被分配角色

  2. 角色(Role):
     - 权限的集合
     - 代表工作职能
     - 例如:管理员、编辑、读者

  3. 权限(Permission):
     - 对资源的操作
     - 例如:读文件、写文件

关系:
  用户 → 角色 → 权限 → 资源

RBAC模型

RBAC模型:

基本模型(RBAC0):
  用户 → 角色 → 权限
  
  用户被分配角色
  角色有权限集合
  用户通过角色获得权限

层次模型(RBAC1):
  角色可以有层次关系
  高级角色继承低级角色权限
  
  例子:
    管理员角色
      ↓ 继承
    编辑角色
      ↓ 继承
    读者角色

约束模型(RBAC2):
  添加约束条件
  例如:
    - 互斥角色:用户不能同时有两个互斥角色
    - 基数约束:角色最多N个用户
    - 时间约束:角色在特定时间有效

统一模型(RBAC3):
  结合层次和约束
  完整的RBAC模型

RBAC示例

RBAC示例:

角色定义:
  管理员(Admin):
    - 所有权限
    - 系统管理
  
  编辑(Editor):
    - 读写文件
    - 修改内容
  
  读者(Reader):
    - 只读文件
    - 查看内容

用户分配:
  用户1:管理员角色
  用户2:编辑角色
  用户3:读者角色

权限检查:
  用户2访问文件:
    1. 检查用户2的角色:编辑
    2. 检查编辑角色的权限:读写
    3. 允许读写操作

角色层次:
  高级管理员
    ↓ 继承
  管理员
    ↓ 继承
  编辑
    ↓ 继承
  读者

约束示例:
  互斥角色:
    - 会计和出纳不能同时担任
    - 防止利益冲突
  
  基数约束:
    - 管理员角色最多3人
    - 防止权限过度集中

RBAC的优势

RBAC优势:

1. 简化管理:
   - 按角色管理权限
   - 不需要为每个用户设置
   - 管理简单

2. 灵活性:
   - 可以灵活分配角色
   - 可以组合角色
   - 适应各种需求

3. 安全性:
   - 最小权限原则
   - 角色分离
   - 约束控制

4. 可扩展性:
   - 容易添加新角色
   - 容易修改权限
   - 适应变化

5. 符合实际:
   - 符合组织架构
   - 符合工作职能
   - 易于理解

使用场景:
  - 企业系统
  - 数据库系统
  - Web应用
  - 现代操作系统

访问控制方法对比

访问控制方法对比:

方法      安全性    灵活性    管理复杂度    适用场景
─────────────────────────────────────────────
DAC        低        高        简单          个人系统
MAC        高        低        复杂          高安全系统
RBAC       中高      中高      中等          企业系统

现代系统:
  - 通常组合使用
  - 基础使用DAC
  - 高安全使用MAC
  - 企业使用RBAC
  - 根据需求选择

8.3 安全机制

安全机制是操作系统实现安全的具体技术和方法。本节详细介绍身份认证、加密技术、审计机制和安全内核等核心安全机制。

8.3.1 身份认证

身份认证(Authentication)是验证用户身份的过程,是系统安全的第一道防线。

身份认证:

定义:
  - 验证用户身份
  - 确认用户是谁
  - 防止未授权访问

认证要素:
  1. 你知道什么(Something you know):
     - 密码
     - PIN码
     - 安全问题

  2. 你拥有什么(Something you have):
     - 智能卡
     - 令牌
     - 手机

  3. 你是什么(Something you are):
     - 指纹
     - 面部
     - 虹膜

单因素认证 vs 多因素认证:
  - 单因素:只用一种方式(如密码)
  - 多因素:组合多种方式(如密码+短信)
  - 多因素更安全

1. 密码认证

密码认证:

定义:
  - 最常用的认证方式
  - 用户名和密码
  - 简单但可能不安全

密码安全:
  1. 强密码要求:
     - 足够长度(至少8位)
     - 包含大小写字母
     - 包含数字和特殊字符
     - 避免常见密码

  2. 密码存储:
     - 不能明文存储
     - 使用哈希函数
     - 加盐(Salt)处理

  3. 密码策略:
     - 定期更换
     - 不能重复使用
     - 复杂度要求
     - 锁定机制

密码哈希:
  存储:hash(password + salt)
  
  登录时:
    1. 用户输入密码
    2. 系统加盐并哈希
    3. 与存储的哈希比较
    4. 匹配则认证成功

例子:
  密码:MyPass123
  盐:random_salt_123
  哈希:SHA256(MyPass123 + random_salt_123)
  存储:hash值和盐值

2. 生物特征认证

生物特征认证:

定义:
  - 使用生物特征识别用户
  - 指纹、面部、虹膜等
  - 难以伪造

类型:
  1. 指纹识别:
     - 最常用
     - 准确度高
     - 成本低

  2. 面部识别:
     - 方便使用
     - 技术成熟
     - 广泛应用

  3. 虹膜识别:
     - 准确度最高
     - 难以伪造
     - 成本较高

  4. 声纹识别:
     - 语音特征
     - 方便但准确度较低

特点:
  优点:
    - 难以伪造
    - 方便使用
    - 不需要记忆

  缺点:
    - 可能被复制
    - 设备成本
    - 隐私问题

使用场景:
  - 手机解锁
  - 门禁系统
  - 高安全系统

3. 智能卡和令牌

智能卡和令牌:

智能卡:
  - 物理卡片
  - 内置芯片
  - 存储密钥或证书

工作过程:
  1. 用户插入智能卡
  2. 系统读取卡片信息
  3. 用户输入PIN码
  4. 验证PIN和卡片
  5. 认证成功

令牌(Token):
  - 硬件或软件设备
  - 生成动态密码
  - 时间同步或事件同步

动态密码:
  - 每60秒变化一次
  - 或每次使用后变化
  - 防止重放攻击

双因素认证:
  1. 密码(你知道什么)
  2. 智能卡/令牌(你拥有什么)
  3. 组合使用,更安全

使用场景:
  - 企业系统
  - 银行系统
  - 高安全环境

4. 多因素认证(MFA)

多因素认证:

定义:
  - 组合多种认证方式
  - 提高安全性
  - 即使一种被破解,仍有保护

常见组合:
  1. 密码 + 短信验证码:
     - 你知道什么 + 你拥有什么
     - 常用组合

  2. 密码 + 智能卡:
     - 你知道什么 + 你拥有什么
     - 企业常用

  3. 密码 + 生物特征:
     - 你知道什么 + 你是什么
     - 高安全系统

  4. 密码 + 短信 + 生物特征:
     - 三种方式组合
     - 最高安全性

工作过程:
  1. 用户输入密码
  2. 系统发送验证码到手机
  3. 用户输入验证码
  4. 验证通过,认证成功

优势:
  - 安全性高
  - 即使密码泄露,仍有保护
  - 适合重要系统

使用场景:
  - 在线银行
  - 企业系统
  - 云服务
  - 现代系统广泛使用

8.3.2 加密技术

加密技术是保护数据机密性的核心技术,将数据转换为不可读形式,只有授权用户可以解密。

加密技术:

目标:
  - 保护数据机密性
  - 防止数据泄露
  - 保护传输和存储

类型:
  1. 对称加密
  2. 非对称加密
  3. 哈希函数
  4. 数字签名

1. 对称加密

对称加密:

定义:
  - 加密和解密使用相同密钥
  - 速度快
  - 适合大量数据

算法:
  1. DES(Data Encryption Standard):
     - 56位密钥
     - 已不安全
     - 被淘汰

  2. AES(Advanced Encryption Standard):
     - 128/192/256位密钥
     - 现代标准
     - 广泛使用

  3. 3DES:
     - DES的改进
     - 三重加密
     - 仍在使用

工作过程:
  1. 发送方:
     - 明文 + 密钥 → 加密算法 → 密文

  2. 传输:
     - 密文传输

  3. 接收方:
     - 密文 + 密钥 → 解密算法 → 明文

密钥管理:
  - 密钥必须安全传输
  - 密钥分发困难
  - 需要安全通道

使用场景:
  - 文件加密
  - 数据库加密
  - 大量数据加密

2. 非对称加密

非对称加密:

定义:
  - 加密和解密使用不同密钥
  - 公钥和私钥
  - 密钥管理容易

密钥对:
  1. 公钥(Public Key):
     - 可以公开
     - 用于加密
     - 任何人都可以获得

  2. 私钥(Private Key):
     - 必须保密
     - 用于解密
     - 只有拥有者知道

算法:
  1. RSA:
     - 最常用
     - 基于大数分解
     - 安全性高

  2. ECC(椭圆曲线加密):
     - 密钥短
     - 效率高
     - 现代应用

工作过程:
  1. 接收方生成密钥对
  2. 公钥公开,私钥保密
  3. 发送方用公钥加密
  4. 接收方用私钥解密

优势:
  - 密钥管理容易
  - 不需要安全通道传输密钥
  - 适合密钥交换

缺点:
  - 速度慢
  - 不适合大量数据

使用场景:
  - 密钥交换
  - 数字签名
  - 小量数据加密

3. 混合加密

混合加密:

定义:
  - 结合对称和非对称加密
  - 发挥各自优势
  - 实际系统常用

工作过程:
  1. 使用非对称加密交换对称密钥
  2. 使用对称加密加密数据
  3. 传输密文和加密的密钥

例子(HTTPS):
  1. 客户端和服务器建立连接
  2. 服务器发送公钥
  3. 客户端生成对称密钥
  4. 用服务器公钥加密对称密钥
  5. 发送加密的对称密钥
  6. 服务器用私钥解密获得对称密钥
  7. 使用对称密钥加密通信

优势:
  - 结合两种加密的优点
  - 密钥管理容易
  - 性能好
  - 安全性高

使用场景:
  - HTTPS
  - VPN
  - 安全通信
  - 现代系统广泛使用

4. 哈希函数

哈希函数:

定义:
  - 单向函数
  - 将任意长度数据映射为固定长度
  - 不可逆

特点:
  1. 单向性:
     - 从哈希值不能恢复原数据
     - 只能正向计算

  2. 确定性:
     - 相同输入产生相同输出
     - 可重复

  3. 雪崩效应:
     - 输入微小变化,输出大变化
     - 难以预测

  4. 抗碰撞:
     - 难以找到两个输入产生相同输出
     - 安全性保证

算法:
  1. MD5:
     - 128位输出
     - 已不安全
     - 不推荐使用

  2. SHA-1:
     - 160位输出
     - 已不安全
     - 不推荐使用

  3. SHA-256:
     - 256位输出
     - 现代标准
     - 广泛使用

应用:
  1. 密码存储:
     - 存储密码哈希值
     - 不存储明文密码

  2. 数据完整性:
     - 计算数据哈希值
     - 验证数据是否被篡改

  3. 数字签名:
     - 对哈希值签名
     - 提高效率

5. 数字签名

数字签名:

定义:
  - 证明数据来源和完整性
  - 不可否认性
  - 类似手写签名

工作过程:
  1. 发送方:
     - 计算数据哈希值
     - 用私钥加密哈希值
     - 发送数据和签名

  2. 接收方:
     - 计算数据哈希值
     - 用公钥解密签名
     - 比较两个哈希值
     - 匹配则验证成功

特点:
  - 证明数据来源
  - 证明数据完整性
  - 不可否认
  - 防止篡改

应用:
  - 软件签名
  - 电子合同
  - 安全通信
  - 证书认证

8.3.3 审计机制

审计机制记录系统活动,追踪用户行为,用于安全事件调查和合规性检查。

审计机制:

定义:
  - 记录系统活动
  - 追踪用户行为
  - 安全事件调查

目标:
  1. 检测安全事件
  2. 调查安全事件
  3. 合规性检查
  4. 威慑作用

审计内容:
  1. 登录和注销
  2. 文件访问
  3. 权限变更
  4. 系统配置修改
  5. 异常行为
  6. 安全事件

审计日志

审计日志:

内容:
  每条日志包含:
    - 时间戳
    - 用户ID
    - 操作类型
    - 操作对象
    - 操作结果
    - IP地址
    - 其他信息

日志示例:
  2024-01-15 10:30:25 user1 login success 192.168.1.100
  2024-01-15 10:31:10 user1 read /home/user1/file.txt success
  2024-01-15 10:32:05 user1 write /home/user1/file.txt success
  2024-01-15 10:35:20 user1 logout success

日志存储:
  - 安全存储
  - 防止篡改
  - 定期备份
  - 长期保存

日志保护:
  1. 只追加:
     - 只能追加,不能修改
     - 防止篡改

  2. 加密存储:
     - 日志加密
     - 防止泄露

  3. 访问控制:
     - 限制访问
     - 只有管理员可以查看

  4. 完整性检查:
     - 定期检查完整性
     - 发现篡改

审计分析

审计分析:

实时分析:
  - 实时监控日志
  - 检测异常行为
  - 及时告警

离线分析:
  - 定期分析日志
  - 发现模式
  - 生成报告

异常检测:
  1. 异常登录:
     - 异常时间登录
     - 异常地点登录
     - 多次失败登录

  2. 异常访问:
     - 访问未授权资源
     - 大量文件访问
     - 异常操作模式

  3. 权限提升:
     - 权限变更
     - 特权操作
     - 可疑活动

报告:
  - 安全事件报告
  - 合规性报告
  - 统计分析报告

审计机制的实施

审计机制实施:

系统级审计:
  - 操作系统记录系统事件
  - 内核审计
  - 系统调用审计

应用级审计:
  - 应用程序记录应用事件
  - 业务逻辑审计
  - 用户行为审计

网络审计:
  - 网络流量记录
  - 网络连接审计
  - 入侵检测

集中审计:
  - 集中收集日志
  - 统一分析
  - 便于管理

工具:
  - syslog(Unix/Linux)
  - Event Viewer(Windows)
  - 第三方审计工具

8.3.4 安全内核

安全内核是操作系统中负责安全的核心部分,实现安全策略和机制。

安全内核:

定义:
  - 操作系统中负责安全的核心
  - 实现安全策略
  - 强制安全机制

位置:
  - 在操作系统内核中
  - 最底层
  - 所有访问都经过

功能:
  1. 访问控制
  2. 身份认证
  3. 审计
  4. 加密
  5. 安全策略实施

安全内核的设计原则

安全内核设计原则:

1. 最小权限:
   - 只给必要权限
   - 减少攻击面
   - 降低风险

2. 完整性:
   - 安全机制完整
   - 不能绕过
   - 强制实施

3. 隔离:
   - 安全功能隔离
   - 防止干扰
   - 独立运行

4. 可验证性:
   - 可以验证正确性
   - 形式化验证
   - 保证安全

5. 最小化:
   - 内核尽可能小
   - 减少漏洞
   - 提高安全性

可信计算基(TCB)

可信计算基(TCB):

定义:
  - 系统中负责安全的组件集合
  - 包括硬件、软件
  - 必须可信

组成:
  1. 硬件:
     - CPU
     - 内存
     - 存储设备

  2. 软件:
     - 操作系统内核
     - 安全模块
     - 关键服务

  3. 固件:
     - BIOS/UEFI
     - 安全芯片

原则:
  - TCB必须可信
  - TCB必须最小化
  - TCB必须可验证

保护:
  - 保护TCB完整性
  - 防止TCB被篡改
  - 定期验证

安全内核的实现

安全内核实现:

参考监视器(Reference Monitor):
  - 所有访问都经过
  - 检查访问权限
  - 强制安全策略

特点:
  1. 完整性:
     - 所有访问都检查
     - 不能绕过

  2. 隔离性:
     - 独立运行
     - 不能被干扰

  3. 可验证性:
     - 可以验证正确性
     - 形式化验证

实现方式:
  1. 内核模块:
     - 作为内核模块
     - 例如:SELinux

  2. 微内核:
     - 安全功能在微内核
     - 更安全

  3. 虚拟机监控器:
     - 在VMM层实现
     - 隔离更好

例子:
  SELinux:
    - Linux安全模块
    - 强制访问控制
    - 安全策略实施

  Windows安全子系统:
    - Windows安全组件
    - 访问控制
    - 身份认证

安全机制总结

安全机制总结:

机制          功能          重要性    实现复杂度
─────────────────────────────────────────
身份认证      验证身份        高        中等
加密技术      保护数据        高        中等
审计机制      记录追踪        中        简单
安全内核      强制安全        高        复杂

综合使用:
  - 身份认证:第一道防线
  - 访问控制:核心机制
  - 加密技术:数据保护
  - 审计机制:事后分析
  - 安全内核:基础保障

现代系统:
  - 综合使用多种机制
  - 多层次防护
  - 纵深防御
  - 提高安全性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值