Appearance
Appearance
1.0 版本发布的要求之一是加入权限分离。此功能可将 Wireshark 解析器代码中任何安全相关缺陷的影响降到最低。
在开发邮件列表的一次讨论中,曾建议采用以下角色: (线程是否正确?2005 年 2 月 07 日:[Ethereal-dev] Ethereal 中的 priv sep)
| 角色 | 权限级别 | 描述 | Capture | 取决于 OS | 读取实时捕获数据 | Dissection | 非特权用户,可能被 chroot | 解析分组数据。Wireshark 中大多数安全相关缺陷都出现在其解析代码中。 | Filesystem | 普通用户 | 普通文件处理,例如读取和写入捕获文件、首选项等。
至少应将 capture 角色分离出来。不过,将 dissection 角色拆分出去会非常有用。
首先,为什么需要提升权限?在许多操作系统上,并不需要。BSD 派生系统提供了一个设备(/dev/bpf),可以让你基于文件权限设置捕获权限。Solaris 通过网络设备(例如 /dev/hme0)提供了类似机制,尽管在混杂模式下捕获可能仍然需要 root 权限。Digital/Tru64 UNIX 也有一种机制允许非 root 用户捕获数据包。两个明显的例外是 Linux 和 Windows。Linux 有 capabilities(特别是 CAP_NET_RAW),但此功能并未被广泛使用。在 Windows 上,看起来 Windows 要求重启后的首次捕获具有 Administrator 权限;请参阅 WinPcap FAQ 中的相关条目。后续捕获(直到下一次重启前)不需要 Administrator 权限。AIX 的行为可能与 Windows 类似;它有 /dev/bpf 设备,这些设备大概可以被赋予相关权限,但 BPF 驱动不会在启动时加载——它必须由 libpcap 加载,而这样做需要 root 权限。此外,BPF 设备在重启后不会保留,因此权限变更也必须由 libpcap 完成,而 libpcap 会创建这些设备。关于各种 OS 上数据包捕获所需权限的详细讨论,请参阅 tcpdump man page。
在 Windows 下如何实现这一点?MSDN 文章 Running with Special Privileges 似乎指向了正确方向。CodeGuru 上的文章 GUI-Based RunAs 也可能有帮助。
OpenSSH 权限分离
Postfix 架构
Secure Programming for Linux and Unix HOWTO
这是 Linux kernel capabilities FAQ
一条关于将 Linux capabilities 与拟议补丁一起使用的开发列表线程
对于捕获角色,创建一个在需要时使用 setuid 的独立程序是否有益?它最初会提供本地捕获,但以后我们也许可以加入远程捕获支持(类似于 WinPcap 的 rpcap 功能)。这样,我们就不必担心在主程序中提升权限。- Gerald Combs
权限分离通常是如何实现的?我们会以较低权限启动 Wireshark,并在需要时提升权限,还是以较高权限启动,然后为不需要它的任务降低权限?- Ulf Lamping
对于捕获部分,我们也许可以使用已经为“实时更新分组列表”实现的机制,因此捕获相关工作总是由一个子任务完成。- Ulf Lamping
至少在 UN*X 上,那个在需要时使用 setuid 的独立程序就是这样工作的——它会被赋予所需的任何权限,并完成所有捕获工作。它不应包含任何 GUI 代码;现在“实时更新分组列表”中的分组计数和停止按钮对话框由子进程处理,而应改为由子进程通过 pipe 将分组计数发送给父进程(注意,我们可能希望 pipe 是非阻塞的,并使用一种允许在数据丢失时重新同步的协议,这样如果父进程无论出于什么原因过于繁忙而无法从 pipe 读取,子进程也不会停滞),并由父进程处理捕获对话框。
这可能会简化捕获代码,因为它不必关心“实时更新分组列表”与非实时捕获之间的区别,也不必关心 select() 与超时。
这在 Windows 上可能更困难——我不知道你会如何向子进程发送相当于信号的东西以使其停止捕获,也不确定是否可以
在 pipe 上拥有等同于非阻塞模式的东西;
将 pipe 的 handle 添加到 GLib 或 Windows main loop 等待的 event handle 集合中。- Guy Harris
在 Windows 上停止捕获子进程没有问题,我几个月前已经用 TerminateProcess 实现过了(好吧,这可能不是最佳方式,但看起来工作得相当好)。
那么,如何把 pipe 设置为非阻塞模式(使用哪些函数,这样我可以稍微读一下文档),它的确切效果是什么?这也能在所有受支持的 unix 版本上工作吗?
第二部分可能更棘手。如果我没记错,Windows 中常用的函数是 WaitForMultipleObjects,但我确实不知道它会如何与 GLib 的事件处理(它的 main loop)相互影响。- Ulf Lamping
TerminateProcess() 会导致进程立即退出——可能是在已经把最后一个数据包的一部分写入捕获文件、但尚未全部写入之后(数据包使用“standard I/O library”例程写入缓冲流,缓冲区会在填满、文件关闭或调用 fflush() 时刷新)——而不给它清理并把数据包最后一部分写入捕获文件的机会;请参阅 MSDN 关于 child processes 的章节。这可能会在读取捕获文件时导致错误。
在 UNX 中,可以通过 fcntl() 设置 O_NONBLOCK,将 pipe 设置为非阻塞模式。我不确定 Windows 上是否存在 UNX 风格的非阻塞模式。
另一种可能性是使用 shared memory 在父进程和子进程之间共享分组计数,并配合某种形式的唤醒——但你需要某种可在窗口系统事件循环中处理的唤醒形式,除非让父进程定期唤醒并更新计数。那可能已经足够了——如果数据包进入速度不是很快,让 Wireshark 每秒左右唤醒一次并在计数变化时更新显示,可能不会浪费多少 CPU 周期;而如果数据包进入速度非常快,计数大概每秒左右本来也会变化。
据我记得,在 Windows 上,如果指定了备用事件源,GLib 的 main loop 使用 MsgWaitForMultipleObjects();在 UN*X 上,它使用 poll()。
在 UN*X 上使用独立的 set-UID 进程执行捕获有一个问题:为了停止捕获,主进程无法向子进程发送信号,因为子进程会以不同的 user ID 运行。它必须找到其他方式来传递异步事件,或者例如通过 pipe 向它发送事件。不幸的是,除非 select() 或 poll() 可以用于子进程的 main loop,否则它无法同时等待数据包和事件——而且不幸的是,Mac OS X 10.4 是不支持在捕获设备上使用 select() 或 poll() 的操作系统之一,因为 BPF 设备是字符设备,而 10.4 不支持在任何字符设备上使用 select() 或 poll()。
另一种可能性是在同一进程中进行捕获,但在支持放弃 set-UID 权限并稍后重新获取这些权限的平台上(例如,saved set-user ID 功能加上 seteuid()),让 Wireshark 在 main() 中做的第一件事就是放弃其 set-UID 权限,然后在枚举网络接口或打开捕获设备时重新获取这些权限——并在枚举接口或打开捕获设备后立即放弃这些权限,以便它以提升权限运行的时间尽可能短。这对 TShark 也会有用,这样它就不必拆分成多个进程。
看起来:
过去几年的 BSD 和 Linux、Digital UNIX 4.0 及更高版本、SunOS 4.1.3 及更高版本、SunOS 5.x、IRIX 6.5(可能也包括更早版本)以及 AIX 4.3 及更高版本支持 seteuid() 和 saved set-user ID 功能;
HP-UX 10.0 及更高版本支持 setresuid()(可用于实现 seteuid())和 saved set-user ID 功能;
因此,我们也许可以在需要支持的所有 UN*X 平台上这样做。-Guy Harris
在同一进程中执行捕获,并且仅在打开捕获设备时以提升权限运行,有一点无法提供:防止解析器问题允许恶意进程注入会提升进程权限的代码(例如使用 seteuid())。-Guy Harris
发到 -users 的一篇帖子包含这个 OpenBSD Wireshark port,可用作起点:http://secure.lv/~nikns/stuff/ports/wireshark-0.99.5.tar--Stephen Fisher
Imported from https://wiki.wireshark.org/Development/PrivilegeSeparation on 2020-08-11 23:13:00 UTC