Linux 集群的安全分发
本文是 LJ 中先前文章的后续,这些文章讨论了分布式安全基础设施 (DSI) 和 Linux 分布式安全模块 (DSM) [参见“Linux 分布式安全模块”,LJ,2002 年 10 月,可在 /article/6215 获取,以及“DSI:用于安全运营商级 Linux 集群的新架构”,可在 www.linuxjournal.com/article/6053 获取]。在本文中,我们重点介绍如何在 DSM 中使用 IP 选项,在分布式环境中为进程级别安全性发送安全信息。我们讨论了网络缓冲区处理、向内核添加钩子、IP 选项和修改 IP 标头。然后,我们介绍了 DSM 中的网络钩子,并展示了一些早期的性能结果。
爱立信研究中心的开放系统实验室启动了开源 DSI 项目,旨在设计和开发针对在 Linux 运营商级集群上运行的软实时电信应用程序的集群安全基础设施。这些集群预计将不间断运行,而无需考虑任何硬件或软件错误。它们必须允许运营商在正常运行期间升级硬件和软件、内核和应用程序,而无需任何计划停机时间,也不会影响提供的服务。
DSI 最初旨在提供运营商级特性,例如可靠性、可扩展性、高可用性和高效性能。此外,它还支持其他几个重要功能,包括连贯的框架、进程级方法以及对抢占式安全和动态安全策略的支持。
DSI 的一个重要功能是其进程级访问控制。当前实施的安全机制基于用户权限,不支持对属于同一用户的两个进程之间的交互进行身份验证检查,即使这些进程是在远程处理器上创建的。对于电信应用程序,只有少数用户会在没有任何中断的情况下长时间运行相同的应用程序。应用上述概念会将相同的安全权限授予在不同节点上创建的所有进程,这导致分布式系统中许多操作没有安全检查。上述安全控制的基本实体的粒度是用户。对于运营商级应用程序,这种粒度是不够的,因此需要更细粒度的基本实体,即单个进程,DSI 中支持了这一点。
DSM 是 DSI 的核心组件,它在 Linux 集群中提供强制访问控制的实现。DSM 负责强制执行访问控制,并使用集群节点中发送进程和节点的安全属性标记 IP 消息。
DSM 作为 Linux 模块使用 Linux 安全模块 (LSM) 钩子实现。开发始于 Linux 内核 2.4.17 以及相应的 LSM 内核补丁。该实现基于 CIPSO 和 FIPS 188 标准,这些标准规定了 IP 标头修改。
DSM 实现的一个重要方面是其分布式性质。集群中的访问控制可以从位于一个节点上的主体执行到位于另一个节点上的资源。因此,需要在同一集群中的节点之间传输安全信息。从安全角度来看,DSM 的分布式性质提供了集群中安全资源的位置透明性。
在这里,我们简要讨论网络缓冲区处理主题,以便更好地理解如何将安全信息嵌入到网络数据包中。我们描述了内核如何处理从应用程序层到硬件层以及反之亦然的网络缓冲区。
图 1 显示了内核中网络数据包的流程。数据包处理发生在两种情况下,即传入数据包和传出数据包。传出的网络数据包处理如下,从应用层开始:应用程序准备要通过网络发送的数据;应用程序向内核发出系统调用以发送数据包;数据包以 sk_buff 结构的形式,通过内核内部的过滤器和路由功能;然后数据包被传递到网络驱动程序,由网络驱动程序将其发送到网卡 (DMA)。
传入的网络数据包,从网卡开始,首先是网卡捕获具有其自身地址或广播地址的网络数据包;然后将其读取到网络内存并生成中断。中断服务例程由硬件中断触发,是网卡驱动程序的一部分,在内核内部运行,它分配一个 sk_buff 并将数据从网卡内存移动到此缓冲区 (DMA)。接下来,数据包被放入 CPU 队列以进行上层处理,并且处理被延迟到稍后启用中断时。最后,数据包通过过滤器和路由功能,并传递到应用层。
基于关于 Linux 内核中如何处理网络缓冲区的通用信息,我们现在演示如何使用此信息来扩展内核安全性。我们研究了添加到 IP 路由功能的钩子,这些钩子允许我们操作 IP 数据包并为 IP 消息添加额外的安全性。
安全模块可以根据安全钩子实现来影响路由决策。在编写路由钩子时,需要记住一些事项,因为这些钩子作为正常的内核函数为每个传入和传出内核的数据包执行。
注册函数的模块必须指定函数在钩子内的优先级。网络过滤器钩子从内核代码中按优先级顺序调用。用户函数可以自由地操作 IP 数据包。用户函数必须返回以下值之一,以便网络代码决定如何处理数据包
NF_ACCEPT:不执行任何操作,让数据包通过网络堆栈。
NF_DROP:丢弃数据包。数据包不会传递以进行进一步处理。
NF_STOLEN:数据包已被获取。数据包不会传递以进行进一步处理。
NF_QUEUE:将数据包排队以进行用户空间处理。
NF_REPEAT:再次调用此钩子。
此函数向我们展示了如何在数据包进入系统之前以及在发送出去之前对其进行操作。我们仍然缺少的是:我们可以向数据包添加哪种信息或选项?如何添加?并且,这些更改是否与当前的实现共存?我们在以下章节中回答这些问题。
关于 Internet 协议的一个鲜为人知的事实是,IP 数据包可以包含可变数量的额外信息(最多 40 字节),这些信息位于标准的 20 字节标头之后。这些扩展字节称为 IP 选项,其中一些选项被定义为携带安全信息。
目前,Internet 协议包括两个安全选项。其中之一是 DoD 基本安全选项(BSO—选项类型 130),它允许使用安全分类标记 IP 数据报。此选项提供 16 个安全分类和可变数量的处理限制。为了处理额外的安全信息,例如安全类别或划分,存在第二个安全选项(ESO—选项类型 133),称为 DoD 扩展安全选项(ESO)。国防信息系统局 (DISA) 负责管理这两个选项中固定字段的值。
计算机供应商现在正在构建具有强制访问控制和多级安全性的商业操作系统。这些系统不再专门为国防或情报部门中的特定群体构建。它们是通常可用的商业系统,可用于各种政府和民用部门环境。
ESO 格式代码的数量很少,无法支持商业安全选项的所有可能应用。BSO 和 ESO 旨在仅支持美国国防部。商业 IP 安全选项 (CIPSO) 旨在支持多种安全策略。Internet 草案提供了支持强制访问控制 (MAC) 安全策略所需的格式和程序。
我们在实现中用于标记数据包的 IP 选项基于 FIPS 188 标准和商业 IP 安全选项 (CIPSO) 草案。在我们的实现中,IP 标头使用这些标准进行更改,因此我们可以将安全信息添加到 IP 标头并通过网络发送。
我们希望使用 IP 选项传输的安全信息是安全 ID (SID) 和安全节点 ID (NID)。DSM 通过提供我们的安全信息作为其 IP 选项来修改每个 IP 数据包。图 2 显示了修改后的 IP 标头的格式。
以下是标头选项列表
CIPSO:一个八位字节,值为 134。
长度:一个八位字节,选项的总长度,包括类型和长度字段。根据当前 IP 标头长度限制为 40 个八位字节,此字段的值不得超过 40。
解释域 (DOI) 标识符:无符号 32 位整数。值 0 保留,不得作为任何 CIPSO 选项中的 DOI 标识符出现。实现应假定 DOI 标识符字段未在任何特定字节边界上对齐。
CIPSO 解释域 (DOI) 字段或 FIPS 188 下的安全标签集名称:设置为十六进制 10001000。此 DOI 值是任意选择的,因为目前此领域没有相关的监管活动。
自由格式:一个八位字节,指示以下字段是标准中未定义的新字段(因此是自由的)。值为 7。
长度:一个八位字节,指示所有标签的总长度。
标签(SID、NID):CIPSO 使用标签集来包含与 IP 数据包中数据相关的安全信息。每个标签都以标签类型标识符开头,后跟标签长度;它以要传递的实际安全信息结尾。
SID 标签:标签 ID:一个八位字节(值 3),标签长度:一个八位字节(值 6),标签数据:32 位 sid 值。
NID 标签:标签 ID:一个八位字节(值 6),标签长度:一个八位字节(值 6),标签数据:32 位 nid 值。
我们使用的 IP 选项是 CIPSO。这些字段未由标准定义,因此可以按照我们定义的方式使用。
解释域 (DOI) 和自由格式(FIPS 188 标准)意味着以下字段是标准中未定义的新字段,因此它们是自由的。
我们在 DSM 中使用了 LSM 安全钩子,以将我们的安全标签添加到 IP 消息中。我们现在通过展示一个应用程序的示例来演示我们如何实现这一点,该应用程序通过写入套接字来发送数据包。该应用程序使用一些库调用。在某个时候,会生成一个系统调用,将消息传递给 Linux 内核。内核套接字实现的入口点是 sys_socketcall() 函数,位于 net/socket.c 中。在调用链中,执行 net/socket.c 中的 sock_sendmsg() 函数(清单 1)。
清单 1. sock_sendmsg()
sock_sendmsg (struck socket *sock, struct msghdr *msg, int size) { int err; struct scm_cookie scm; err = security_ops->socket_ops->sendmsg(sock, msg, size); if(err) return(err); ... }
该函数中的首批操作之一是执行安全钩子(security_ops->socket_ops->sendmsg(...))。此钩子最终进入 DSM 套接字钩子,该钩子修改 IP 数据包,如清单 2 所示。
清单 2. dsi_socket_sendmsg()
int dsi_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { ... inode_security_t *isec; struck sock sk; struct ip_options *opt = NULL; int optlen = NSID_BASE_LEN + NSID_SSID_LEN + NSID_NODEID_LEN; //8 +_6 + 6 unsigned char optptr[optlen]; ... sk = sock->sk; opt = sk->protinfo.af_inet.opt; dsi_options_fill (isec, optptr, optlen); dsi_ip_options_get(&opt, optptr, optlen); opt = xchg(&sk->protinfo.af_inet.opt, opt); ... }
函数 dsi_options_fill 按照上一段中的规定将安全信息设置为缓冲区。稍后,在后续函数中,此安全信息作为选项附加到 IP 消息。SID 源自套接字安全 ID,NID 对整个节点是全局的——无需将其作为参数传递给函数。
在此操作之后,添加了安全信息的修改后的数据包将转发以在内核中进行正常处理,并最终通过网络发送。在接收端,传入的消息存储在 sk_buff 结构中,并在一系列函数和钩子中进行预处理。其中一个函数是 /net/ipv4/ip_options.c 中的 ip_options_compile(清单 3),其中处理选项。
清单 3. ip_options_compile ()
int ip_options_compile (struct ip_options *opt, struct sk_buff *skb) { unsigned char *pp_ptr; unsigned char *optptr; ... case IPOPT_CIPSO: if(security_ops->ip_ops->decode_options(skb, optptr, &pp_ptr) goto error; break; ... }
对于 CIPSO 情况,将调用安全钩子 decode_options。此钩子被 DSM dsi_decode_options 钩子替换,其中从传入数据包中读取安全参数(SID、NID),并存储在附加到此 sk_buff 的安全结构中。填充了安全信息的 sk_buff 缓冲区附加到接收套接字队列,它们在队列中等待被接收应用程序读取。为了读取它们,应用程序发出系统调用 sys_socketcall (),就像发送数据包时一样。调用再次通过 DSM 安全钩子,在其中根据传入数据包的 sk_buff 安全性验证接收套接字安全 ID。如果套接字不允许接收具有给定安全 ID 的数据包,则这些数据包将被丢弃。清单 4 显示了 include/net/sock.h 中的内核函数。
清单 4. sock_queue_rcv_skb ()
int sock_queue_rcv_skb (struct sock *sk, struct sk_buff *skb) { int err=0; ... err=security_ops->socket_ops->sock_rcv_skb (sk, skb); if(err) return (err); ... }
正如我们所见,调用了安全钩子 sock_rcv_skb。当加载 DSM 时,此钩子随后被 DSM 函数 dsi_sock_rcv_skb 替换。在此函数中,执行安全验证。从示例代码中我们可以看到,需要完成工作来操作安全标签。
我们进行了多次基准测试,以验证向 IP 标头添加选项是否会影响整体性能以及影响程度。一项测试是在集群节点之间发送 UDP 数据包,并测量性能下降,这包括发送端的数据包安全修改,包括接收端的数据包安全提取。基于我们实现的添加额外安全性的平均开销为 30%。大部分开销(约 25%)与基于 IP 安全选项的 IP 数据包修改有关。剩余的开销(约 5%)由 Linux 内核中的安全钩子基础设施贡献,例如套接字钩子。正如我们所见,大部分开销与基于 IP 选项的 IP 数据包修改有关,只有一小部分开销是由安全钩子基础设施引起的。
我们未来的努力将 направлены на 改进 IP 修改算法,因为我们将继续使用 IP 选项作为安全传输机制。
通过更改 IP 选项,我们能够使用 DSM 将安全信息分发到集群的节点。我们优化了 IP 数据包修改,我们的主要结果显示出显着改进——30% 的开销已降至 14%。这些性能结果令人鼓舞,我们看到了更多进一步优化的机会,以实现更低的开销。然而,结果表明了高效分布式安全开发面临的挑战。我们希望您试用 DSI 和 DSM 并向我们发送您的反馈。
参考文献
DSI 和 DSM 主页:www.linux.ericsson.ca/dsi
FIPS 188:csrc.nist.gov/publications/fips/fips188.html
Linux 数据包过滤器:/article/4852 和 /article/5617
LSM:lsm.immunix.org
网络缓冲区:/article/1312
开放系统实验室:www.linux.ericsson.ca
SE Linux:www.nsa.gov/selinux
Ibrahim Haddad 是 LJ 的特约编辑,是加拿大蒙特利尔爱立信研究院研究与创新部门的研究员。他为 Richard Peterson 的两本书做出了贡献,Red Hat Linux 口袋管理员 和 Red Hat 企业 Linux 和 Fedora 版本:完整参考(DVD 版),由 McGraw-Hill/Osborne 出版。
Miroslaw Zakrzewski 在加拿大蒙特利尔的爱立信公司工作,开发新一代 CDMA 系统。可以通过 Miroslaw.Zakrzewski@Ericsson.ca 与他联系。