PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

环境说明

  无

前言


  只要装过各种系统的人都或多或少会接触到UEFI或者BIOS这样的概念。本文也不会对这些概念进行详解,本文主要把这些概念串起来,并引入MOK(Machine Owner Key)。

  为什么需要MOK,是因为在使用现代linux系统时(如:PVE),如果我们需要自己安装一些自己构建的驱动(例如想实现gpu sr-iov),会用到此功能。

UEFI/BIOS


  BIOS (Basic Input/Output System) 和UEFI (Unified Extensible Firmware Interface) 这两个名字或者功能我们非常的熟悉了,机器开机自检完成后,一般f2/del等进入的界面,就是这个系统在显示工作。如果我们不按f2/del等键,系统会默默运行BIOS或者UEFI,然后自动加载引导程序,然后加载OS来运行。

  UEFI主要是为了取代BIOS系统的,因为其有:支持更多分区、启动速度快、支持更多硬件、更加安全、维护简单(统一标准)等等优点。其有个大的缺点就是,有些时候会因为安全的问题,需要更多的设置过程。

  对于BIOS来说,机器开机自检完成后,自动读取MBR(Master boot record),一般在磁盘的开始的扇区,然后加载OS或者其他进行启动。注意,这里MBR分区是一种老旧的分区格式了。

  对于UEFI来说,机器开机自检完成后,自动读取GPT分区(GUID Partition Table)中的EFI分区,然后加载OS或者其他进行启动。

  总的来说,随着时间的推进,UEFI是一种标准,已经被各大厂商支持和实现了。BIOS其已经完成了其历史的作用,除了为了兼容老机器,否则我们不应该使用它。

Linux 在UEFI下,自构建驱动安装问题


  这里有一个背景知识,那就是现代的linux内核,在加载内核驱动的时候,一般都会对内核驱动做一系列校验,其中一项就是做签名校验,如果校验失败,内核拒绝加载驱动。对于这部分内容,可以参考《Linux驱动加载源码分析(安全加载 、签名、校验)》 https://www.cnblogs.com/Iflyinsky/p/18301894 一文。

  在《常用加密及其相关的概念、简介(对称、AES、非对称、RSA、散列、HASH、消息认证码、HMAC、签名、CA、数字证书、base64、填充)》 https://www.cnblogs.com/Iflyinsky/p/18076852 中我们介绍了签名的原理,这里简单提一下:首先有非对称加密算法生成公钥、私钥。然后对消息进行摘要,对摘要进行私钥加密得到签名,最后可以用公钥来验证(解密)此签名是否正确。

  那么对应到内核驱动签名验证这里就是:首先对驱动模块使用私钥进行签名,并将签名文件写入驱动模块文件中,当我们加载驱动模块时,内核会使用其带的公钥来对驱动模块进行签名验证。

  注意,这里有一个重要的问题是:内核带的公钥是哪里来的?一般来说,有两个渠道可以增加内核的公钥,一个是编译内核的时候,一个是通过运行时的一些方法动态写入一些公钥到内核。

Machine Owner Key


  在实际我们自己测试自己的驱动模块的时候,一般都会自己生成一个私钥,公钥对来对自己的驱动模块进行签名。但是在启用的UEFI+ 支持安全启动的linux系统上,我们的驱动模块是无法正常加载的,因为我们的驱动无法过签名验证。

  从上面的描述来看,如果要成功加载我们的内核模块,那么我们应该把我们的公钥传给内核。

  在解决怎么把公钥传给内核前,我们第一步要简单了解一下linux secure boot的简单流程:

  • 机器开机及硬件自检完成,然后进入uefi固件,uefi固件里面有微软公钥。
  • uefi加载shim固件(独立与linux发行版,被微软私钥预先签名,例如这个包: https://packages.debian.org/sid/amd64/shim-signed )。此外shim有各大发行版公钥。
  • shim固件加载grub固件(grub固件被各大发行版私钥签名)。
  • grub加载linux签名内核。

  其实从上面的流程来看,就是一环环签名校验,保证了信任链的传递。

  回到我们之前的问题,我们怎么把我们私钥、公钥传给内核呢?必定是有一个工具能够将相关信息传进去,这个工具就是mokutil工具。

mokutil

  简而言之,shim除了自带发行版的公钥外,还维护一个用户可以操作的密钥数据库,里面存储的是Machine Owner Key。通过mokutil工具,我们可以增加和删除这些密钥。这样我们就可以将我们自己的模块签名公钥嵌入到了UEFI启动流程中去,然后根据适当的方法即可交给内核使用,并能够加载我们自己密钥签名的驱动程序。

  mokutil工具添加过程:

  1. 导入公钥
mokutil --import /var/lib/dkms/mok.pub
# 并输入一次性密码
  1. 重启系统,此时新一次的uefi的启动流程会启动mok管理器,让用户按照要求注册新的密钥,并输入之前的一次性密码。(弹个框,自己选择,输入密码即可)

  2. 这样启动系统后,我们的密钥成功加载。

  3. 测试系统是否成功注册密码

mokutil --test-key /var/lib/dkms/mok.pub

  这样我们就可以使用mok.pub对应的私钥对我们的驱动进行签名,然后就可以正常使用公钥验证,然后加载驱动了。

  此外,这里还要多提一下,其实android的安全加载也有类似的过程,也是两个要点:信任链传递、驱动签名。

后记


  了解了越来越多计算机的知识,不得不感叹:知识总是不经意间出现在日常生活工作中。

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

Linux安全启动及Machine Owner Key(UEFI BIOS MBR GPT GRUB)的更多相关文章

  1. UEFI,BIOS,MBR,

    UEFI启动是一种新的主板引导项,正被看做是有近20多年历史的BIOS 的继任者.顾名思义,快速启动是可以提高开机后操作系统的启动速度.由于开机过程中UEFI的介入 第一:安全性更强 UEFI启动需要 ...

  2. linux开机启动详细流程图

    linux开机启动详细流程图: 一.BIOS 加电自检当你按电源开关开机时,电脑会首先去启动BIOS(基本输入输出系统),BIOS一般是集成在主板上的.BIOS 的工作1.检测连接硬件,比如显卡,内存 ...

  3. Linux内核启动过程概述

    版权声明:本文原创,转载需声明作者ID和原文链接地址. Hi!大家好,我是CrazyCatJack.今天给大家带来的是Linux内核启动过程概述.希望能够帮助大家更好的理解Linux内核的启动,并且创 ...

  4. Linux内核启动

    Linux内核启动过程概述 Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解的东西很多.毕竟Linux内核是由很多人,花费了巨大的时间和精力写出来的.而且直到现在,这 ...

  5. 【转载】简述Linux的启动过程

    原文:简述Linux的启动过程 本文将简单介绍一下Linux的启动过程,希望对那些安装Linux的过程中遇到了问题的朋友有些帮助 声明:本人没用过UEFI模式和GPT分区格式,所有关于这两部分的内容都 ...

  6. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  7. andriod and linux kernel启动流程

    虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makefile,讲一下boot ...

  8. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  9. Linux 开机启动顺序_005

    ***了解Linux开机启动顺序之前先了解一下Linux运行级别,通过inittab配置文件查看运行级别的定义: [root@oldboy ~]# cat /etc/inittab # Default ...

  10. 【内核】linux内核启动流程详细分析

    Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码, 主要作用 ...

随机推荐

  1. python377和python27的区别?

    python27无法解释print(1,2,3,sep="*"),Windows命令行窗口运行会报语法错误:无效语法  SyntaxError:invalid syntax pyt ...

  2. requests + tkinter 获取网页数据

    代码: from tkinter import * import requests window = Tk() window.geometry('500x350+500+100') window.ti ...

  3. .NET Core应用程序每次启动后使用string.GetHashCode()方法获取到的哈希值(hash)不相同

    前言 如标题所述,在ASP.NET Core应用程序中,使用string.GetHashCode()方法去获取字符串的哈希值,但每次重启这个ASP.NET Core应用程序之后,同样的字符串的哈希值( ...

  4. iOS线程While-True死循环会发生什么

    一.在工作的代码有一段while-True轮训的逻辑,循环中主要的工作是阻塞的IO 代码大概如下: dispatch_async(dispatch_get_global_queue(0, 0), ^{ ...

  5. HMI-Board上手指南

    介绍 HMI-Board为 RT-Thread 联合瑞萨推出的高性价比图形评估套件,取代传统的 HMI+主控板硬件,一套硬件即可实现 HMI+IoT+控制的全套能力.依托于瑞萨高性能芯片 RA6M3 ...

  6. OOP第一阶段题集总结

    一.前言 知识点:数组,字符串的使用,链表,hashmap,泛型的使用,正则表达式的使用,类的设计,类与类之间的关系,单一职责. 题量:题目数量为5+4+3,数量适中,其中都是前几题较简单,最后一题较 ...

  7. 未能加载文件或程序集“SissPayWebApi”或它的某一个依赖项。试图加载格式不正确

    "未能加载文件或程序集"xxx"或它的某一个依赖项.试图加载格式不正确的程序."这个错误可能在IIS或VS中出现,一般是平台和dll版本不一致导致的. 一.VS ...

  8. AlertManager解析:构建高效告警系统

    本文深入探讨了AlertManager的技术细节和实际应用,从基本概念.核心组件.工作流程,到与Prometheus的集成和实战案例,旨在为专业人士提供一个全面的AlertManager技术和应用指南 ...

  9. 没有 Git,如何下载 Gitee 代码?

    目录 没有 Git,如何下载 Gitee 代码? 注册 Gitee 账号 下载代码压缩包 没有 Git,如何下载 Gitee 代码? 鉴于看我博客的人很多都是大学本科生.非 CS 专业,大部分人都不会 ...

  10. version `GLIBC_2.14' not found 问题解决

    参考连接:https://blog.csdn.net/u011262253/article/details/99056385