当前位置: 首页 > news >正文

ARM MCU-制作Linux rootfs

在Linux嵌入式开发和自定义系统中,在编译了Linux Kernel后,需要定制一套操作界面Shell,也就是给Kernel组合一个强大的操作系统的外衣, 就是Ubuntu/Redhat他们基于同样的Kernel, 但发布不一样的版本一样。

Ubuntu Base是一个最小化的根文件系统,适用于创建定制化的系统镜像。它支持多种架构(如 i386、amd64、armhf、arm64 等),并广泛用于嵌入式开发和自定义系统构建。

本文参考123的基础上总结。

rootfs制作过程

1.1 准备工作

首先需要下载适合目标架构的Ubuntu Base压缩包,例如ubuntu-base-16.04.6-base-arm64.tar.gz。然后创建一个目录用于解压文件系统:

mkdirraw-rootfssudotar-xpfubuntu-base-16.04.6-base-arm64.tar.gz-Craw-rootfs/

如果宿主机与目标架构不同,需要安装 QEMU 模拟器:

sudoapt-getinstallqemu-user-staticsudocp/usr/bin/qemu-aarch64-static raw-rootfs/usr/bin/sudocp/etc/resolv.conf raw-rootfs/etc/

1.2 配置和挂载

为了进入chroot环境,需要挂载必要的文件系统。可以创建一个挂载脚本mount.sh

#!/bin/bashmnt(){echo"MOUNTING"sudomount-tproc /proc$2/procsudomount-tsysfs /sys$2/syssudomount-obind/dev$2/devsudomount-obind/dev/pts$2/dev/pts}umnt(){echo"UNMOUNTING"sudoumount$2/procsudoumount$2/syssudoumount$2/dev/ptssudoumount$2/dev}if["$1"=="-m"]&&[-n"$2"];thenmnt$1$2elif["$1"=="-u"]&&[-n"$2"];thenumnt$1$2fi

赋予脚本执行权限并挂载:

chmod+x mount.sh /mount.sh-mraw-rootfs/

进入chroot环境:

sudochrootraw-rootfs

1.3 系统更新与安装

chroot环境中,更新软件包并安装必要的工具:

aptupdateaptupgradeaptinstall-ysystemdvimgit

如果需要安装桌面环境,例如Xubuntu

apt-getinstallxubuntu-desktop

1.4 添加用户和设置密码

创建用户并设置密码:

useradd-s'/bin/bash'-m-Gadm,sudo usernamepasswdusernamepasswdroot

1.5 制作最终的 RootFS 镜像

退出chroot环境并取消挂载:

exit/mount.sh-uraw-rootfs/

创建根文件系统映像:

ddif=/dev/zeroof=linuxroot.imgbs=1Mcount=1024sudomkfs.ext4 linuxroot.imgmkdirrootfssudomountlinuxroot.img rootfs/sudocp-rfpraw-rootfs/* rootfs/sudoumountrootfs/ e2fsck-p-flinuxroot.img resize2fs-Mlinuxroot.img

最终生成的linuxroot.img即为定制化的Ubuntu根文件系统映像,可用于嵌入式设备或其他应用场景。

附1:创建回环文件说明

环回(loopback)文件系统是Linux类系统中非常有趣的部分。我们通常是在设备上(例如磁盘分区)创建文件系统。这些存储设备能够以设备文件的形式来使用,比如 /dev/device_name。为了使用存储设备上的文件系统,我们需要将其挂载到一些被称为挂载点(mount point)的目录上。环回文件系统是指那些在文件中而非物理设备中创建的文件系统。我们可以将这些文件作为文件系统挂载到挂载点上。这实际上可以让我们在物理磁盘上的文件中创建逻辑磁盘。

我们的目的:创建一个回环文件模拟一个大小10GB的物理磁盘,并在该回环镜像中分两个区:

  • UEFI分区,大小500M,FAT32格式。
  • 根分区(/),大小剩余大小,EXT4格式。

2.1 创建镜像文件

也就是创建一个大小10G的文件。

$ddif=/dev/zeroof=ubuntu_base.imgbs=1Gcount=10记录了10+0 的读入 记录了10+0 的写出10737418240bytes(11GB,10GiB)copied,84.1916s,128MB/s

你会发现创建好的文件大小超过了1GB。这是因为硬盘作为块设备,其分配存储空间时是按照块大小的整数倍来进行的。此时可以直接对这个文件作为一整个分区格式化并使用,用mkfs命令将1GB的文件格式化成ext4文件系统:

$mkfs.ext4 ubuntu_base.img

可使用下面的命令就可看到已经是文件系统了:

$fileubuntu_base.img loobackfile.img: Linuxrev1.0ext4 filesystem data,UUID=3be1775c-8976-445d-9134-8daabb2bade7(extents)(64bit)(large files)(huge files)

现在就可以挂载环回文件了:

$sudomkdir/mnt/loopback$sudomount-oloop ubuntu_base.img /mnt/loopback

-o loop用来挂载环回文件系统。这实际上是一种快捷的挂载方法,我们无需手动连接任何设备。但是在内部,这个环回文件连接到了一个名为/dev/loop1loop2的设备上。我们也可以手动来操作:

$sudolosetup /dev/loop1 ubuntu_base.img$sudomount/dev/loop1 /mnt/loopback

使用下面的方法进行卸载(umount):

$sudoumount/mnt/loopback

也可以用设备文件的路径作为umount命令的参数:

$sudoumount/dev/loop1

以上是将整个文件作为一个分区使用的方法,但我们的目的是在该文件内分多个区,继续。

2.2 建立分区

a.分区方式一

建立分区可以使用fdiskparted工具,本人比较喜欢用parted,对于设置启动分区非常方便。

$sudopartedubuntu_base.img GNU Parted3.2使用 /home/work/loobackfile.img 欢迎使用 GNU Parted!输入'help'可获得命令列表.(parted)

新建UEFI分区。对于UEFI启动方式,首先要设置创建label为msdos;

(parted)mklabel msdos

创建分区大小500M:

(parted)mkpart primary fat320500MB

查看新创建的分区,该分区编号为1:

(parted)p Model:(file)磁盘 /home/work/ubuntu_base.img:10.7GB Sector size(logical/physical): 512B/512B 分区表:msdos Disk Flags: 数字 开始: End 大小 类型 文件系统 标志1512B 500MB 500MB primary fat32 lba(parted)

将该分区设置为boot(UEFI启动)分区:

(parted)set1boot on(parted)p Model:(file)磁盘 /home/work/ubuntu_base.img:10.7GB Sector size(logical/physical): 512B/512B 分区表:msdos Disk Flags: 数字 开始: End 大小 类型 文件系统 标志1512B 500MB 500MB primary fat32 启动, lba(parted)

设置后通过p命令可以看到,标志处多了启动(boot)标志。

将剩余空间创建根分区:

(parted)mkpart primary ext4 500MB100%

到此两个分区创建完毕,使用p查看,q保存退出:

(parted)p Model:(file)磁盘 /home/work/ubuntu_base.img:10.7GB Sector size(logical/physical): 512B/512B 分区表:msdos Disk Flags: 数字 开始: End 大小 类型 文件系统 标志1512B 500MB 500MB primary fat32 启动, lba2500MB10.7GB10.2GB primary ext4 lba

b.分区方式二

使用parted分区,需要自己计算大小,对齐等,难免有些麻烦,可以使用sfdisk来简化分区,得到上述同样的分区效果只需执行:

sudosfdisk--force/dev/sdc<<EOF 1,500M,0x0c,* 500M,,0x83 EOF

sfdisk会从标准输入读取分区描述信息;每一行描述一个分区,常用格式为:<起始柱面>,<柱面数 量>,<分区ID>,< bootable >。如果参数没有指定,则使用默认值;而<起始柱面>的默认值为当前最小可用的柱面编号。

  • 1,500M,0x0c,*表示的是,从1扇区开始,分配大小为500M的一个分区,分区类型为0x0c表示fat32,'*'标识这是一个启动分区。
  • 500M,,0x83表示从500M大小开始,分配大小为自动分配,即剩余所有大小作为一个分区,0x83表示这是一个ext分区。

2.3 映射分区设备并格式化

镜像文件已经被分为两个区,但是还没有格式化,要对内部的两个分区进行格式化就需要先将两分区挂载到设备。有一个更快的方法可以挂载镜像中的所有分区——kpartx。它并没有安装默认在系统中,你得使用软件包管理器进行安装:

$sudoapt-getinstallkpartx

执行以下命令自动挂载镜像文件中的分区:

$sudokpartx-v-aubuntu_base.imgaddmap loop0p1(253:0):0976562linear7:01addmap loop0p2(253:1):019994624linear7:0976896

这条命令在磁盘镜像中的分区与/dev/mapper中的设备之间建立了映射,随后便可以格式化/挂载这些设备。格式化两个分区:

$sudomkfs.fat-F32/dev/mapper/loop0p1#loop0p1 回环设备的分区1$sudomkfs.ext4 /dev/mapper/loop0p2#loop0p1 回环设备的分区2

2.4 挂载分区

格式换完成后就可以挂载两个分区:

$sudomkdir/mnt/loopback $sudomount/dev/mapper/loop0p2 /mnt/#挂载根分区$sudomkdir-p/mnt/loopback/boot/efi $sudomount/dev/mapper/loop0p1 /mnt/boot/efi#挂载uefi启动分区

附2:Security Boot

Secure Boot 的核心是数字签名验证,确保只有经过授权的代码(如Bootloader、内核、驱动模块)才能被执行。其工作流程如下:

3.1 启动验证流程

  1. 硬件启动→ UEFI固件加载。
  2. 验证Bootloader→ 检查Bootloader(如GRUB、Windows Boot Manager)的签名是否在DB中,且不在DBX中。
  3. 验证OS内核→ Bootloader进一步验证内核(如Linux Kernel、Windows NTOSKRNL)的签名。
  4. 验证驱动模块→ 内核验证加载的驱动(如Linux的.ko、Windows的.sys)是否受信。
  5. 启动完成→ 若所有步骤通过,系统正常启动;否则拒绝执行并报错。

3.2 Secure Boot 的实际应用

a. Windows/Linux

  • Windows:默认启用Secure Boot,使用微软的PK和KEK签名Bootloader(如bootmgfw.efi)。

    • 若安装未签名的Linux发行版(如某些Arch Linux变种),需在UEFI中禁用Secure Boot或手动导入签名。
  • Linux(如Ubuntu)

    • Ubuntu的Bootloader和内核已由Canonical签名,兼容Secure Boot。

    • 自定义内核需用sbsign工具签名:

      sbsign--keydb.key--certdb.crt--outputvmlinuz-signed vmlinuz

b. Android 设备

  • AVB(Android Verified Boot):基于Secure Boot的扩展,验证boot.imgsystem.img的完整性。
    • 如果篡改系统分区(如Root),设备会进入Orange State(警告状态)或直接拒绝启动。
    • 例如:Pixel手机的eFuse会记录解锁状态,影响DRM(如Netflix HD播放)。

c. 嵌入式设备(路由器、IoT)

  • U-Boot + FIT签名
    • 许多路由器(如OpenWRT设备)使用FIT(Flattened Image Tree)格式的镜像,U-Boot会验证其签名。
    • 若签名不匹配,设备可能进入Recovery模式或变砖。
  • 苹果T2芯片:Mac电脑的Secure Boot由T2芯片管理,仅允许苹果签名的系统启动。

3.3. Secure Boot 的绕过与破解

尽管Secure Boot提高了安全性,但仍有潜在绕过方式:

a. 物理攻击

  • 禁用Secure Boot:通过UEFI设置(需BIOS密码)。
  • 刷写未签名固件:如树莓派(默认无Secure Boot)或部分x86设备。

b. 密钥泄露

  • 导入自定义PK

    • 攻击者若获取设备的管理权限(如Intel ME漏洞),可注入恶意PK。

    • 例如:

      # 在Linux中导入自定义PKmokutil--importPK.der

c. 签名漏洞

  • 利用过期/弱签名:某些厂商可能使用弱算法(如SHA-1)或未吊销旧密钥。
  • Bootkit攻击:如BlackLotus UEFI恶意软件曾利用微软签名的漏洞绕过Secure Boot。

3.4. 如何配置与管理 Secure Boot

a. 检查 Secure Boot 状态

  • Linux

    mokutil --sb-state# 输出 "SecureBoot enabled" 表示已启用
  • Windows

    Confirm-SecureBootUEFI# PowerShell命令

b. 自定义密钥(以Ubuntu为例)

  1. 生成密钥

    openssl req-newkeyrsa:4096-nodes-keyoutPK.key-outPK.csr openssl x509-signkeyPK.key-inPK.csr-outPK.crt-days3650
  2. 导入密钥到固件

    mokutil--importPK.crt# 需重启并在MOK(Machine Owner Key)界面确认
  3. 签名内核

    sbsign--keyPK.key--certPK.crt--output/boot/vmlinuz-signed /boot/vmlinuz

c. 完全禁用 Secure Boot

  • 进入UEFI/BIOS设置→ 找到Secure Boot选项→ 选择Disabled(不推荐,降低安全性)。

2.5. Secure Boot 的局限性

  • 依赖硬件支持:老旧设备(如传统BIOS)无法使用。
  • 用户体验复杂:用户自行安装未签名系统时需手动管理密钥。
  • 无法防御所有攻击:如DMA攻击(通过Thunderbolt注入恶意代码)或固件漏洞(如Intel TXT缺陷)。

2.6. mokutil 工具精要说明

mokutilMachine Owner Key utility)是一个Linux命令行工具,用于管理UEFI Secure BootMOK(Machine Owner Key,机器所有者密钥)。它的主要功能包括:

  • 导入/删除自定义密钥(用于签名内核、模块等)。
  • 查看Secure Boot状态
  • 管理MOK列表(允许或禁止特定密钥)。

a. 常用命令

# 检查Secure Boot是否启用mokutil --sb-state# 导入自定义密钥(需重启确认)mokutil--import/path/to/key.der# 列出已注册的MOK密钥mokutil --list-enrolled# 删除MOK密钥mokutil--delete/path/to/key.der

b. MOK 的作用

  1. 允许用户自定义信任的密钥

    • Secure Boot默认只信任厂商预置的密钥(如微软、Canonical的密钥)。
    • 通过MOK,用户可以添加自己的密钥(如自签名内核或驱动模块的密钥),而无需修改UEFI的全局数据库(db/dbx)。
  2. 避免直接操作UEFI固件

    • 修改UEFI的PK/KEK/DB通常需要进入BIOS设置,而MOK通过Shim在操作系统层面管理,更灵活。
  3. 防止恶意软件篡改

    • MOK的修改需在重启时通过MOK Manager(一个图形化界面)确认,防止攻击者静默注入密钥。在MOK Manager界面要求输入的密码,既不是密钥的密码,也不是BIOS密码或Linux root密码,而是在通过mokutil导入密钥时用户预先设置的临时密码。以下是详细说明:

      • 谁设置的密码?
        用户在通过mokutil --import导入密钥时,必须手动输入并确认一个密码(例如:sudo mokutil --import key.der会提示输入密码)。

      • 何时需要输入?
        系统重启后,在MOK Manager界面(蓝屏或黑屏的UEFI风格界面)中会提示输入该密码,以确认密钥导入操作。

http://www.jsqmd.com/news/692516/

相关文章:

  • FPGA时钟设计避坑指南:以紫光PGL22G的PLL为例,聊聊IP核配置的那些细节
  • 3个场景彻底解决Windows风扇噪音:FanControl智能散热管理实战指南
  • 从PCIe到NVMe:为什么你的SSD必须实现这6个Capability?一次讲清硬件兼容性
  • LaTeX数学公式到Word的技术迁移方案:MathJax与OMML的桥接实现
  • 如何高效管理Navicat试用期:macOS平台终极解决方案指南
  • 在线3D模型查看器:5个简单步骤快速上手浏览器端3D可视化
  • 2026年论文AI率超90%怎么办?亲测实用的四款工具,最后一款必收藏 - 降AI实验室
  • 成人如何挑选优质维生素D3?2026十大权威维生素D3榜单,助力钙质吸收强健骨骼 - 博客万
  • AutoDock Vina终极指南:5分钟学会分子对接的免费开源神器
  • 等保三级合规:企业级智能体全链路数据安全落地方案 —— 2026年企业级AI Agent安全架构实战
  • 中电金信X四川农商银行打造分布式核心系统建设样板
  • 用Pandas搞定股票每日收益率计算:从简单收益率到对数收益率,新手避坑指南
  • API攻防-接口类型SOAPOpenAPI导入项目识别WSDL解析JSON解析联动扫描器
  • 别再傻傻分不清!一张图看懂宝马底盘代号E、F、G、U系列的区别与演变
  • 如何快速实现微信自动化:wxauto工具的完整使用指南
  • 别再瞎调了!用MATLAB的Bayesopt工具箱给XGBoOST自动调参,效率提升10倍
  • 2026洛阳商务宴请与江浙菜定制:诱江南官方电话+深度品牌横评避坑指南 - 优质企业观察收录
  • 从零手写C++ MCP网关:2小时搭建支持100万并发连接的轻量级架构原型(含完整ASIO+RingBuffer+FlatBuffers代码骨架),现在不学,下次大促你就得通宵改bug!
  • 5个理由告诉你:为什么Formily是构建复杂表单的终极解决方案!
  • 2026亲测!10款免费高效降AI率工具:降低AI率效果排行榜(值得收藏) - 降AI实验室
  • 从EDA工具视角看PrimeTime:那些被忽略的约束检查项与内部机制
  • 100000000000
  • 高温天出门怎么防晒能不黑?Leeyo防晒霜持久防晒海边疯玩也不黑 - 全网最美
  • 机器学习不平衡分类评估指标全解析
  • 如何免费快速配置APA第7版格式:新手5分钟上手完整教程
  • CefFlashBrowser终极指南:如何拯救你的Flash游戏和童年记忆
  • 告别手动计算坐标!用LVGL的lv_obj_align与lv_obj_align_to打造自适应UI布局(附STM32工程实例)
  • 2026年黑龙江、吉林、辽宁耐寒牡丹苗批发采购指南:园林绿化与高端庭院造景完全方案 - 年度推荐企业名录
  • Day2 C语言基础
  • 5家有自主研发技术的GEO服务商,企业选型怎么选? - 品牌测评鉴赏家