第21章 其他文件系统
附录 D. OpenPGP 密钥
24.2.FreeBSD 更新
及时应用安全补丁和升级到最新版本的操作系统是维护计算机软件的重要任务。在 FreeBSD 引入了 freebsd-update 工具之后这便不再是问题了。
支持 FreeBSD 的二进制安全和勘误更新,而不需要手动编译和安装补丁或新内核。二进制更新适用于目前安全团队所支持的所有架构和版本。支持的版本列表和它们的预计终结日期列在 https://www.FreeBSD.org/security/
这个工具可以把二进制的安全和勘误更新直接应用于 FreeBSD 的基本系统,而不需要重新编译和安装修补或新内核。目前由安全性团队提供支持的二进制更新可用于所有的架构和发行版。支持的版本列表和它们的预计结束日期列在 https://www.FreeBSD.org/security/
注意:
如果有使用 crontab 来执行 freebsd-update(8),则必须在升级操作系统前先关闭它。
本节描述了 freebsd-update 使用的配置文件,演示了如何应用安全补丁以及如何升级到一个次要或主要的操作系统版本,并讨论了升级操作系统时的一些注意事项。

24.2.1.配置文件

使用 freebsd-update 的默认配置文件就能正常更新,有些用户可能希望通过调整配置文件 /etc/freebsd-update.conf 中的默认配置来更好地控制升级的过程。可用的参数在文档中介绍的很详细,但下面的这些可能需要进一步的解释:
1
# Components of the base system which should be kept updated.
2
Components world kernel
Copied!
这个参数是控制 FreeBSD 的哪一部分将被保持更新。默认的是更新整个基础系统和内核。也可以指定个别组件,例如 src/basesrc/sys 。然而最好的选择是把这个选项保留为默认值,因为如果要修改它去包含一些指定的选项,就需要用户列出每一个想要更新的项目。这可能会引起可怕的后果,因为部分的源代码和二进制程序得不到同步。
1
# Paths which start with anything matching an entry in an IgnorePaths
2
# statement will be ignored.
3
IgnorePaths /boot/kernel/linker.hints
Copied!
要想在更新过程中不改动指定的目录,例如 /bin/sbin ,可以在该语句中添加它们的路径。这个选项可以用来防止 freebsd-update 覆盖本地的修改。
1
# Paths which start with anything matching an entry in an UpdateIfUnmodified
2
# statement will only be updated if the contents of the file have not been
3
# modified by the user (unless changes are merged; see below).
4
UpdateIfUnmodified /etc/ /var/ /root/ /.cshrc /.profile
Copied!
这个选项将只更新指定目录中未修改的配置文件。用户所做的任何修改都会阻止这些文件的自动更新。还有一个选项,KeepModifiedMetadata ,它将指示 freebsd-update 在合并过程中保存更改。
1
# When upgrading to a new FreeBSD release, files which match MergeChanges
2
# will have any local changes merged into the version from the new release.
3
MergeChanges /etc/ /var/named/etc/ /boot/device.hints
Copied!
带有配置文件的目录列表,freebsd-update 应该尝试合并这些文件。文件合并过程是一系列类似于 mergemaster(8)diff(1) 补丁,但选项较少。合并后要么接受、打开一个编辑器,要么导致 freebsd-update 中止。如果有疑问,可以备份 /etc 并接受合并。关于 mergemaster 的更多信息,参见 mergemaster(8)
1
# Directory in which to store downloaded updates and temporary
2
# files used by FreeBSD Update.
3
# WorkDir /var/db/freebsd-update
Copied!
这个目录是放置所有补丁和临时文件的。用户做一个版本升级的话,请确认此处至少有 1 GB 的可用磁盘空间。
1
# When upgrading between releases, should the list of Components be
2
# read strictly (StrictComponents yes) or merely as a list of components
3
# which *might* be installed of which FreeBSD Update should figure out
4
# which actually are installed and upgrade those (StrictComponents no)?
5
# StrictComponents no
Copied!
当设置成 yes 时,freebsd-update 将假设这个 Components 列表时完整的,并且对此列表以外的项目不会修改。实际上就是 freebsd-update 会尝试更新 Componets 列表里的每一个文件。

24.2.2.安全补丁

应用 FreeBSD 安全补丁的过程被简化了,管理员能够使用 freebsd-update 来保持系统的完整补丁。更多有关 FreeBSD 安全报告的资讯可以参考 FreeBSD 安全报告
可以通过下列命令来下载和安装 FreeBSD 的安全补丁。第一条命令将确定是否有任何未完成的补丁,如果有的话,将列出在安装补丁时将被修改的文件。第二条命令将安装这些补丁。
1
# freebsd-update fetch
2
# freebsd-update install
Copied!
如果更新安装了任何内核补丁,系统都将需要重启,以便启动到打了补丁的内核。如果该补丁安装于任何正在运行的二进制文件,受影响的应用程序应重新启动,以便使用二进制文件的补丁版本。
注意:
通常情况下,用户需要准备好重启系统。要知道内核更新是否需要重启,可以执行 freebsd-version -kuname -r 命令,如果不同,则需要重启。
可以通过在 /etc/crontab 中添加这个语句,将系统配置为每天自动检查一次更新:
1
@daily root freebsd-update cron
Copied!
如果存在补丁,它们将被自动下载,但不会被应用。root 用户将被发送一封电子邮件,这样就可以通过 freebsd-update install 来查看和手动安装补丁。
如果出现了错误,可以使用下面的 freebsd-update 命令回退到上一次的修改:
1
# freebsd-update rollback
2
Uninstalling updates... done.
Copied!
同样,如果内核或任何内核模块被修改,系统应该被重新启动,任何受影响的二进制文件也应该被重新启动。
只有 GENERIC 内核可以被 freebsd-update 自动更新。如果安装的是自定义内核,那么在 freebsd-update 完成安装更新后,必须重新编译并安装。默认的内核名称是 GENERICuname(1) 命令可以用来验证它的安装。
/boot/GENERIC 中始终保留一份 GENERIC 内核的备份。它在诊断各种问题和进行版本升级时都会有帮助。请参阅 FreeBSD 9.X 及更高版本的自定义内核 ,以了解如何获得 GENERIC 内核的副本。
除非 /etc/freebsd-update.conf 中的默认配置已更改,否则 freebsd-update 将安装更新的内核源代码以及其余更新。重新编译安装一个新的自定义内核可以按照常规方法进行。
通过 freebsd-update 发布的更新有时并不会涉及内核。如果在执行 freebsd-update install 的过程中内核代码没有进行变动,就没有必要重新编译内核了。不过,由于 freebsd-update 每次都会更新 /usr/src/sys/conf/newvers.sh 文件,而修订版本 (uname -r 报告的 -p 数字) 来自这个文件,因此,即使内核没有发生变化,重新编译内核也可以让 uname 报告准确的修订版本。在维护许多系统时这样做会比较有帮助,因为这一信息可以迅速反映机器上安装的软件更新情况。

24.2.3.重大和次要的更新

从 FreeBSD 的一个次要版本升级到另一个版本,比如从 FreeBSD 9.0 升级到 FreeBSD 9.1 ,被称为次要版本(Minor version)升级。当 FreeBSD 从一个主要版本(Major version)升级到另一个主要版本时(重大更新),例如从 FreeBSD 9.X 到 FreeBSD 10.X ,这两种类型的升级都可以通过提供 freebsd-update 的发布版本目标来完成。
如果系统正在运行一个自定义的内核,在开始升级之前,请确保在 /boot/GENERIC 中有一份 GENERIC 内核的备份。请参考 FreeBSD 9.X 及以后版本的自定义内核 ,以了解如何获得 GENERIC 内核的备份。
下面的命令在 FreeBSD 9.0 系统上运行时,会将其升级到 FreeBSD 9.1:
1
# freebsd-update -r 9.1-RELEASE upgrade
Copied!
在收到命令后,freebsd-update 将评估配置文件和当前系统,试图收集必要的信息来执行升级。屏幕上将显示哪些组件已经被检测到,哪些没有。比如说:
1
Looking up update.FreeBSD.org mirrors... 1 mirrors found.
2
Fetching metadata signature for 9.0-RELEASE from update1.FreeBSD.org... done.
3
Fetching metadata index... done.
4
Inspecting system... done.
5
6
The following components of FreeBSD seem to be installed:
7
kernel/smp src/base src/bin src/contrib src/crypto src/etc src/games
8
src/gnu src/include src/krb5 src/lib src/libexec src/release src/rescue
9
src/sbin src/secure src/share src/sys src/tools src/ubin src/usbin
10
world/base world/info world/lib32 world/manpages
11
12
The following components of FreeBSD do not seem to be installed:
13
kernel/generic world/catpages world/dict world/doc world/games
14
world/proflibs
15
16
Does this look reasonable (y/n)? y
Copied!
此时,freebsd-update 将尝试下载所有升级所需的文件。在某些情况下,用户可能会被提示关于要安装什么或如何继续的问题。
若使用自定义内核,上述的步骤将会产生如下的警告:
1
WARNING: This system is running a "MYKERNEL" kernel, which is not a
2
kernel configuration distributed as part of FreeBSD 9.0-RELEASE.
3
This kernel will not be updated: you MUST update the kernel manually
4
before running "/usr/sbin/freebsd-update install"
Copied!
此时可以安全地忽略此警告。更新后的 GENERIC 内核将用作升级过程的中间步骤。
所有的补丁下载到本地后,会开始安装。这个过程可能需要一些时间,取决于机器的速度和工作量。然后,配置文件将被合并。合并过程需要一些用户干预,因为文件可能会被合并,或者屏幕上会出现一个编辑器进行手动合并。在这个过程中,每次成功的合并结果都会显示给用户。合并失败或被忽略将导致进程中止。用户可能希望对 /etc 做一个备份,并在以后手动合并重要的文件,如 master.passwdgroup
注意:
所有的补丁和合并都在另一个目录中进行,并不会直接修改。所有的补丁都被成功安装之后,所有的配置文件都被合并,之后,用户就可以用下面的命令将这些更改提交到磁盘上。
1
# freebsd-update install
Copied!
内核和内核模块将首先被打上补丁。如果系统运行的是一个自定义的内核,使用 nextboot(8) 来设置下一次启动的内核为更新的 /boot/GENERIC
1
# nextboot -k GENERIC
Copied!
警告:
若机器在远程进行更新,请在使用 GENERIC 内核重新开机前,请确定该内核含有所有系统所需的驱动程序以正常开机并连线至网络。特别是在运行的自定义内核有使用到由核心模组提供的内建功能,请确保使用 /boot/loader.conf 工具将这些模块临时加载到 GENERIC 内核中。建议禁用非必要的服务,以及任何磁盘和网络挂载,直到升级过程完成。
现在可以用更新后的内核引导系统了:
1
# shutdown -r now
Copied!
在系统重新上线后,需要再次运行 freebsd-update。升级的状态被保存着,这样 freebsd-update 就无需重头开始,但是会删除所有旧的共享库和目标文件。执行如下命令继续这个阶段的升级:
1
# freebsd-update install
Copied!
注意:
取决与是否有库的版本更新,通常只有 2 个而不是 3 个安装阶段。
升级程序现在完成了。如果所做的是主要的版本升级,则需跟据主要版号升级后的套件升级说明重新安装所有的 Port 和 Packages 。

24.2.3.1.在 FreeBSD 9.X 及之后版本自定义内核

在使用 freebsd-update 前,请确定在 /boot/GENERIC 已有 GENERIC 内核的备份。如果只编译过一次自定义内核,那么 /boot/kernel.old 就是 GENERIC 内核,只需要将该目录重新命名为 /boot/kernel
如果编译自定义内核过超过一次,或已经不晓得编译过的次数,则需取得与目前操作系统版本相符的 GENERIC 内核版本。若可直接操作实体系统,则可以从安装媒体取得 GENERIC 内核备份:
1
# mount /cdrom
2
# cd /cdrom/usr/freebsd-dist
3
# tar -C/ -xvf kernel.txz boot/kernel/kernel
Copied!
或者,可以从源代码重新编译 GENERIC 内核:
1
# cd /usr/src
2
# make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null
Copied!
这个内核要被 freebsd-update 识别为 GENERIC 内核,GENERIC 配置文件必须不能做任何修改,也建议在编译内核时不要使用其他特殊选项。
freebsd-update 仅需要 /boot/GENERIC 存在便可,因此不须重新开机进入 GENERIC

24.2.3.2.主要版号升级后的套件升级

一般来说,已安装的应用程序在次要版本升级后仍可正常运行。但主要版本升级会采用不同的应用程序二进制接口(Application Binary Interfaces, ABIs),会导致大部份第三方应用程序无法正常运行。因此在主要版本升级后,需要升及所有已安装的 Package 和 Port,Package 可以使用 pkg upgrade 来升级,而 Port 则需使用 ports-mgmt/portmaster 工具。
对所有已安装的软件包进行强制升级时,即使版本号没有增加,也会用软件库中的新版本替换这些软件包。这是因为在FreeBSD的主要版本之间进行升级时,ABI版本会发生变化。强制升级可以通过执行以下操作来完成:
1
# pkg-static upgrade -f
Copied!
重新编译所有已安装的应用程序可以执行以下指令来完成:
1
# portmaster -af
Copied!
这个命令将显示每个有可配置选项的应用程序的配置在屏幕上,并等待用户进行选择。若想避免这种情况并使用预设的配置选项,可在上述指令加上 -G 参数。
完成软件升级后,需执行一次 freebsd-update 来完成最后的升级过程:
1
# freebsd-update install
Copied!
如果临时使用了 GENERIC 内核,这时就需要按照配置 FreeBSD 内核的说明编译并安装一个新的自定义内核。
重启进入新的 FreeBSD 版本,升级过程便正式完成。

24.2.4.系统状态对照

已安装的 FreeBSD 版本状态可以使用 freebsd-update IDS 与另一个已知良好的备份来做比对测试。这个指令会评估目前版本的系统工具,库和配置文件,并可以作为一个内置的入侵检测系统 (Intrusion Detection System, IDS) 。
警告:
这个指令并非用来取代真正的 IDS,如 security/snort 。由于 freebsd-update 储存在磁盘上,存在被窜改的可能性,虽然这个可能性会因使用 kern.securelevel 以及将 freebsd-update 在不使用时以只读储存而降低,但是最好的解决方案是系统能够与安全磁盘 (如 DVD 或外部 USB 设备) 进行比较。替代的方式是使用内置工具的 IDS 功能,在 二进制验证 中有详细说明。
这里开始比较,需指定输出文件用来保存结果:
1
# freebsd-update IDS >> outfile.ids
Copied!
现在开始系统会被检查,并生成一份包含了文件和它们的SHA256哈希值的清单。
这个文件中有非常长的行,但输出的格式很容易分析。举例来说,要获得一份与发行版中不同哈希值的文件列表,可以使用如下的命令:
1
# cat outfile.ids | awk '{ print $1 }' | more
2
/etc/master.passwd
3
/etc/motd
4
/etc/passwd
5
/etc/pf.conf
Copied!
这份输出是删节缩短后的,其实有更多的文件。其中有些文件并非由人为修改造成,比如 /etc/passwd 被修改是因为添加了用户进系统。在某些情况下,还有另外的一些文件,诸如内核模块与 freebsd-update 的不同是因为它们被更新过了。为了把指定的文件或目录排除在外,把它们加到 /etc/freebsd-update.confIDSIgnorePaths 选项中即可。