应用安全补丁是计算机软件维护的一个重要组成部分, 特别是针对操作系统来说。 长期以来, 对于 FreeBSD 来说, 这都不是一件很容易做到的事情。 必须先把补丁修补到源代码上, 再编译成二进制代码, 然后才安装补丁。
现在, FreeBSD 引入 freebsd-update
工具, 应用补丁不再那么麻烦。
这个工具提供两种功能: 首先支持直接把二进制的安全更新与勘误更新
(errata updates) 应用到 FreeBSD 基本系统, 而不需要重新编译安装。
其次是这个工具还支持主要与次要发行版本间的升级。
目前, 二进制更新支持所有安全小组所支持的所有架构的正式发行版。
在升级到一个新的正式发行版本之前, 应先阅读目标正式发行版的发行公告,
因为它们可能包含有关目标升级版本的重要消息。
这些发行公告可以通过以下链接查阅:
http://www.FreeBSD.org/releases/
。
如果 crontab
中存在有用到 freebsd-update(8)
特性的部分, 那么在下面的操作开始以前, 必须先禁用它们。
有些用户可能希望调整 /etc/freebsd-update.conf
中的默认配置, 从而更好的控制升级过程。 可用的选项在文档中有详细介绍,
但下面这些可能需要更多的解释:
# Components of the base system which should be kept updated. Components src world kernel
这个参数是控制 FreeBSD 的哪些部分会被更新。 默认更新源代码、
整个基本系统和内核。 组件同样也是可控制的, 举个例子,
这里加入 world/games
就会允许应用游戏相关的补丁。
使用 src/bin
则是允许更新
src/bin
目录中的源代码。
这个选项最好保持默认值, 因为如果指定了任何参数, 那么就需要用户列出所有需要更新的项目。 这可能会带来灾难性的后果, 因为未指定部分的源代码和二进制程序将得不到更新。
# Paths which start with anything matching an entry in an IgnorePaths # statement will be ignored. IgnorePaths
添加指定路径, 比如 /bin
或
/sbin
这将能让这些指定的目录在更新过程中不被修改。
这个选项能够防止本地的修改被 freebsd-update
工具覆盖。
# Paths which start with anything matching an entry in an UpdateIfUnmodified # statement will only be updated if the contents of the file have not been # modified by the user (unless changes are merged; see below). UpdateIfUnmodified /etc/ /var/ /root/ /.cshrc /.profile
更新时跳过指定目录或配置文件。 用户指定的配置文件都会使这些文件的自动更新失效。
还有另外一个选项, KeepModifiedMetadata
,
这能让 freebsd-update
在合并时另存修改。
# When upgrading to a new FreeBSD release, files which match MergeChanges # will have any local changes merged into the version from the new release. MergeChanges /etc/ /var/named/etc/
freebsd-update
会尝试合并列表中配置文件。
文件合并的过程是一系列类似 mergemaster(8) 的 diff(1) 补丁格式,
但更少选项。 要么接受合并, 要么打开一个文件编辑器,
或者终止 freebsd-update
。
如果不能确定, 可以先备份 /etc
, 然后接受合并。
有关 mergemaster
的更多信息请参阅:
Section 23.7.12.1, “mergemaster
” 。
# Directory in which to store downloaded updates and temporary # files used by FreeBSD Update. # WorkDir /var/db/freebsd-update
这个目录是存放所有补丁和临时文件的地方。 一般情况下, 用户做一个版本间升级时, 则至少要保证这个目录有 1 GB 的可用磁盘空间。
# When upgrading between releases, should the list of Components be # read strictly (StrictComponents yes) or merely as a list of components # which *might* be installed of which FreeBSD Update should figure out # which actually are installed and upgrade those (StrictComponents no)? # StrictComponents no
当这个选项设置成 yes
时,
freebsd-update
将假设这个
组件 (Components)
列表是完整的,
不再尝试修改此列表以外的。 默认情况下,
freebsd-update
将会尝试更新
组件
列表里的每一个文件。
FreeBSD 安全补丁可以通过以下命令下载并安装补丁:
#
freebsd-update fetch
#
freebsd-update install
如果补丁涉及到内核, 那么系统需要重启以应用补丁。 否则,
则可以将应用补丁的任务可以交给 cron(8) 由其每夜执行
freebsd-update
更新。
这可以在 /etc/crontab
中添加:
@daily root freebsd-update cron
这条记录说明由 cron
每天运行一次
freebsd-update
工具。
使用 freebsd-update
检测是否有可用更新,
如果有可用更新, 那么它们会被自动下载到本地磁盘,
但它们不会被自动更新。
root
用户将会收到一份需要手动安装更新的电子邮件。
如果更新出错, 可以使用以下命令让
freebsd-update
回滚到更新前:
#
freebsd-update rollback
一旦完成更新, 如果内核或任何一个内核模块被修改的话, 就需要重启系统。 让 FreeBSD 加载新的二进制文件。
使用 GENERIC
内核的情况下,
freebsd-update
会自行更新内核, 无需用户干涉。
如果使用的是自定义内核, 则它必须重新编译并安装新内核。
不过这种情况下, freebsd-update
依旧会检测是否存在 GENERIC
内核,
如果 /boot/GENERIC
存在,
即使它不是正在运行的系统内核, 也会更新它。
保存一份 GENERIC
内核的副本在
/boot/GENERIC
目录中是个明智的选择。
这可以诊断很多问题,
以及在 Section 23.2.3, “主要和次要版本的升级” 中介绍的使用
freebsd-update
更新系统时会很有用。
除非修改了 /etc/freebsd-update.conf
里的默认配置,
否则, freebsd-update
会更新的内核源代码以及其余部分。
重新编译并安装自定义内核, 可以按照通常方式进行。
通过 freebsd-update
分发的补丁并不是每次都会涉及内核更新。
如果执行 freebsd-update install
时内核源码没有变动,
就必要重新构建内核了。 不过, 由于 freebsd-update
每次都会更新 /usr/src/sys/conf/newvers.sh
文件,
补丁版本号 (uname -r
报告的 -p
数字)
就是来自这个文件, 因此, 即使内核没有发生变化,
重新编译内核也可以让 uname(1) 准确报告补丁版本。
这在维护多个系统的时候这样会比较有用,
因为这一信息可以迅速反映判定更新情况。
升级 FreeBSD 时, 从一个次要版本升级到另一个次要版本, 就像 FreeBSD 9.0 升级到 FreeBSD 9.1 , 被称作次要版本升级。 次要版本升级后已安装的应用程序一般都可以继续工作。
当 FreeBSD 从一个 主要版本 升级到另一个主要版本时, 就像 FreeBSD 8.X 升级到 FreeBSD 9.X , 这个过程中会删除旧的目标文件和库, 这将导致绝大部分第三方应用程序无法继续使用, 所以建议在升级前卸载所有已安装的 ports 软件, 或者升级完成后使用 ports-mgmt/portmaster 工具, 强制重装所有已安装应用程序。 输入以下命令重装所有软件:
#
portmaster -af
这将确保所有的第三方应用程序都会被正确的安装。
请注意将环境变量 BATCH
被设置为 yes
时,
整个过程中出现的所有询问, 都会自动应答 yes
,
重建过程将不再需要人工干预。
如果您正在使用一个自定义内核, 那么升级过程会稍微复杂些, 而且根据使用的 FreeBSD 版本的不同, 可能升级过程也会有些差异。
您需要将一份 GENERIC
内核副本放到
/boot/GENERIC
。
如果系统中没有 GENERIC
内核,
可以通过以下方法获取:
如果只编译过一次内核, 则 /boot/kernel.old
中的内核实际上就是 GENERIC
内核。
重命名为 /boot/GENERIC
就可以了。
如果可以直接接触到物理计算机,
则可以通过安装介质直接安装 GENERIC
内核。
从安装介质执行以下命令安装:
#
mount /cdrom
#
cd /cdrom/X.Y-RELEASE/kernels
#
./install.sh GENERIC
替换 X.Y-RELEASE
为您正使用的版本。
GENERIC
内核默认会被安装到
/boot/GENERIC
目录中。
如果以上方法都不可行, 则还可以使用源代码来重新编译和安装
GENERIC
内核:
#
cd /usr/src
#
env DESTDIR=/boot/GENERIC make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null
#
mv /boot/GENERIC/boot/kernel/* /boot/GENERIC
#
rm -rf /boot/GENERIC/boot
如果希望 freebsd-update
工具能够正确识别
GENERIC
内核,
您必须确保没有对 GENERIC
内核配置文件进行过任何修改。
此外, 建议您取消任何其他特殊的编译选项。
上述步骤并不需要使用这个
GENERIC
内核来重新引导系统。
如果只编译过一次内核, 则 /boot/kernel.old
内核实际上就是 GENERIC
内核。
重命名为 /boot/kernel
就可以了。
如果可以直接接触到物理计算机,
则可以通过安装介质直接安装 GENERIC
内核。
从安装介质执行以下命令安装:
#
mount /cdrom
#
cd /cdrom/usr/freebsd-dist
#
tar -C/ -xvf kernel.txz boot/kernel/kernel
如果以上方法都不可用, 还可以使用源代码来重新编译和安装
GENERIC
内核:
#
cd /usr/src
#
make kernel __MAKE_CONF=/dev/null SRCCONF=/dev/null
如果希望 freebsd-update
工具能够正确识别
GENERIC
内核,
您必须确保没有对 GENERIC
内核配置文件进行过任何修改。
此外, 建议您取消任何其他特殊的编译选项。
上述步骤并不需要使用这个
GENERIC
内核来重新引导系统。
主要和次要版本都是可以通过在 freebsd-update
命令后面指定一个正式发行版的参数来升级的,
以下是一个升级到 FreeBSD 9.1 的例子:
#
freebsd-update -r 9.1-RELEASE upgrade
这个命令被执行后, freebsd-update
工具将会解析配置文件并评估当前的系统, 以获取执行升级所需的必要信息。
并回显已检测到的和未检测到的组件列表。 例如:
Looking up update.FreeBSD.org mirrors... 1 mirrors found. Fetching metadata signature for 9.0-RELEASE from update1.FreeBSD.org... done. Fetching metadata index... done. Inspecting system... done. The following components of FreeBSD seem to be installed: kernel/smp src/base src/bin src/contrib src/crypto src/etc src/games src/gnu src/include src/krb5 src/lib src/libexec src/release src/rescue src/sbin src/secure src/share src/sys src/tools src/ubin src/usbin world/base world/info world/lib32 world/manpages The following components of FreeBSD do not seem to be installed: kernel/generic world/catpages world/dict world/doc world/games world/proflibs Does this look reasonable (y/n)? y
此时, freebsd-update
工具将会尝试下载所有升级所需文件。
某些情况下, 用户可能被问及需安装些什么和如何进行之类的问题。
当使用自定义内核时, 上面的步骤会产生类似下面的警告:
WARNING: This system is running a "MYKERNEL
" kernel, which is not a
kernel configuration distributed as part of FreeBSD 9.0-RELEASE.
This kernel will not be updated: you MUST update the kernel manually
before running "/usr/sbin/freebsd-update install"
此时, 您可以暂时安全地无视这个警告。 更新的 GENERIC
内核将会在升级过程的中间步骤中使用。
在下载完成针对本地系统的补丁之后, 这些补丁会被应用到系统上。
这个过程需要消耗的时间取决于您计算机的性能及负载情况。
这个过程中将会对配置文件所做的改动进行合并, 文件可能会自动合并,
也可能在屏幕上显示一个编辑器, 用于手工完成合并操作。
在处理过程中, 合并成功的结果会显示给用户。 失败或被忽略的合并,
则会导致这一过程终止。 用户可能会希望保留一份 /etc
的备份,
并在这之后手工合并重要的文件, 例如 master.passwd
和
group
文件。
系统至此尚未被修改, 所有的补丁和合并工作都是在另外一个目录中进行的。 当所有的补丁都被成功的应用上了以后, 所有的配置文件都被合并后, 一旦这个步骤完成后, 使用以下的命令将升级后的文件安装到磁盘上:
#
freebsd-update install
内核和内核模块会被首先应用上补丁。 此时, 您必须重新启动计算机。
如果您使用的是自定义内核, 请使用 nextboot(8) 命令临时指定下一次引导使用
/boot/GENERIC
内核:
#
nextboot -k GENERIC
在使用 GENERIC
内核启动前,
请确保它包含了用于引导系统所需的全部驱动程序
( 如果您是远程进行升级操作, 还应确保网卡驱动也是存在的 )。
需要特别注意的是,
如果之前的内核中静态编译了通常以内核模块形式存在的驱动程序,
则一定要通过 /boot/loader.conf
机制来将这些模块加载到
GENERIC
内核上。
此外, 通常建议您您临时禁用不太重要的服务、 磁盘和网络挂载服务等等,
直至升级过程完成。
现在可以重启更新内核了:
#
shutdown -r now
在系统重新上线后, 需要再次运行 freebsd-update
工具。
这会删除所有旧的共享库和目标文件, 但是升级状态会被保存,
这样再次运行 freebsd-update
工具就不需要重头开始了。
#
freebsd-update install
取决于是否有库版本更新, 通常只有 2 个而不是 3 个安装阶段。
一个主要版本升级完成后, 所有的第三方软件都应该被重新编译和安装。 这是因为已安装的软件可能依赖于已在升级过程中被删除的库。 这个重建过程可以使用 ports-mgmt/portmaster 工具自动化实现:
#
portmaster -f
一旦完成这个步骤, 再最后一次运行 freebsd-update
工具来结束升级过程。 执行以下命令处理升级中的所有细节:
#
freebsd-update install
如果您使用临时的 GENERIC
内核来引导系统的,
那么现在可以按照通常方法重新编译并安装新自定义内核了。
重新启动计算机进入新版本的 FreeBSD , 至此升级过程全部完成。
freebsd-update
工具也可被用来对照当前系统与一个已知完好的 FreeBSD 拷贝的差异。
这个工具可以评估的系统工具, 库和配置文件。 使用以下的命令开始对照:
#
freebsd-update IDS >> outfile.ids
这个命令的名称是 IDS ,
它并不能代替真正的入侵检测系统 (如: security/snort) ,
因为 freebsd-update
工具的数据存储在磁盘上,
很显然它们有被篡改的可能。 当然也可以使用一些方法来降低被篡改的可能性,
比如设置 kern.securelevel
和不使用时将 freebsd-update
工具的数据存储在只读文件系统上,
例如 DVD 或安全的外置 USB
磁盘上。
系统会立即开始检测, 并生成一份包含了文件和它们的 sha256(1)
哈希值的清单, 已知发行版中的值与当前系统中安装的值将会被输出送到
outfile.ids
文件中。
这个文件行数非常冗长, 但输出的格式很清晰。 举例来说, 要获得一份与发行版中不同哈希值的文件列表, 可使用以下命令获得:
#
cat outfile.ids | awk '{ print $1 }' | more
/etc/master.passwd /etc/motd /etc/passwd /etc/pf.conf
这份输出时删节缩短后的, 其实是有更多的文件。 其中有些文件并非人为修改,
比如 /etc/passwd
被修改可能是系统添加了新用户。
在某些情况下, 还有另外的一些文件, 诸如内核模块与
freebsd-update
数据不同是因为它们被更新过了。
为了将指定的文件或目录排除在外, 可以把它们加到
/etc/freebsd-update.conf
中的
IDSIgnorePaths
参数中。
除了前面讨论过的部分之外, 这也能被当作是对升级方法的一种详细补充。
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.