ID: 364 类型:基础 | 状态:未完成 |
描述
软件使用引入竞争条件的信号处理程序。
扩展描述
竞争条件经常发生在信号处理程序中,因为信号处理程序支持异步操作。这些竞争状况有多种根本原因和表现。攻击者可能能够利用信号处理程序争用条件导致软件状态损坏,可能导致拒绝服务甚至代码执行。
当不可重入函数或状态敏感操作在信号处理程序中发生时,就会出现这些问题,在信号处理程序中可以随时调用它们。这些行为可能违反被中断的“常规”代码或其他可能被调用的信号处理程序所做的假设。如果在不适当的时刻调用这些函数(例如,当一个不可重入函数已经在运行时),可能会发生内存损坏,这可能会被利用来执行代码。当在信号处理程序中调用free时,通常会出现另一个信号争用条件,这会导致双重空闲,因此会产生一个任意写入的情形。即使给定指针在释放后设置为空,在释放内存和将指针设置为空之间仍存在争用条件。如果为多个信号设置了相同的信号处理程序,这就特别有问题,因为这意味着信号处理程序本身可以重新输入。
有几个已知的与接收到“信号处理程序竞争条件”标签的信号处理程序相关的行为:
•信号处理程序和“常规”代码都可以访问的共享状态(例如全局数据或静态变量)
- 信号处理程序和其他信号处理程序之间的共享状态
- 在信号处理程序中使用不可重入功能——这通常意味着正在使用共享状态。例如,malloc()和free()是不可重入的,因为它们可能使用全局或静态数据结构来管理内存,并且它们被无辜的表面函数(如syslog())间接使用;这些函数可能会因内存损坏和代码执行而被利用。
- 同一信号处理函数与多个信号的关联-这可能意味着共享状态,因为访问相同的代码和资源。例如,这可能是双重免费的来源,并在免费后使用弱点。
- 使用setjmp和longjmp,或其他阻止信号处理程序将控制返回到原始功能的机制
- 虽然在技术上不是争用条件,但某些信号处理程序设计为最多调用一次,并且多次调用可能会导致安全问题,即使没有对信号处理程序的任何并发调用。这可能是一个来源,双重释放和释放后使用的弱点。
- 信号处理程序漏洞通常是基于缺少特定保护机制而进行分类的,尽管在CWE中不鼓励这种类型的分类,因为程序员通常可以选择几种不同的机制来解决弱点。这种保护机制可能保留对共享资源的访问的排他性,以及相关代码的行为原子性:
•避免共享状态
•在信号处理器中使用同步
•在常规代码中使用同步
•禁用或屏蔽其他信号,提供原子性(有效地确保排他性)
相关视图
与“研究层面”视图(CWE-1000)相关
与“开发层面”视图(CWE-699)相关
引入模式
阶段 | 说明 |
架构与设计 | |
实现 |
应用平台
语言
C (有时出现)
C++ (有时出现))
后果
范围 | 冲击 | 可能性 |
完整性 | 技术冲击: 修改应用数据 修改内存; DoS: 崩溃、推出或者重启: 执行未获授权的代码或命令 可能会导致数据损坏,并可能通过在意外的时间修改全局变量或数据结构来执行任意代码,这违反了使用此全局数据的代码的假设。 | |
访问控制 | 技术冲击: 获得特权或获得身份 如果信号处理程序中断了以特权执行的代码,那么信号处理程序也可能以提升的特权执行,这可能会使后续的攻击更加严重。 |
被利用的可能性:
一般
示例
例1
此代码用两个不同的信号(CWE-831)注册相同的信号处理程序功能。如果这些信号被发送到进程,处理程序将创建一条日志消息(在程序的第一个参数中指定)并退出。(问题代码)
Example Language: C
char *logMessage;
void handler (int sigNum) {
syslog(LOG_NOTICE, "%s\n", logMessage);
free(logMessage);
/* artificially increase the size of the timing window to make demonstration of this weakness easier. */
sleep(10);
exit(0);
}
int main (int argc, char* argv[]) {
logMessage = strdup(argv[1]);
/* Register signal handlers. */
signal(SIGHUP, handler);
signal(SIGTERM, handler);
/* artificially increase the size of the timing window to make demonstration of this weakness easier. */
sleep(10);
}
handler函数使用全局状态(globalvar和logmessage),它可以由sightup和sigterm信号调用。攻击场景可能遵循以下几行:
•程序开始执行,初始化logmessage,并注册信号处理程序以进行叹息和sigterm。
•程序开始其“正常”功能,简化为sleep(),但可能是任何需要一段时间的功能。
•攻击者发送sighup,调用handler(称为“sighup handler”)。
•Sightup处理程序开始执行,调用Syslog()。
•syslog()调用malloc(),这是不可重入的。malloc()开始修改元数据以管理堆。
•然后攻击者发送sigterm。
•叹息处理程序被中断,但Syslog的malloc调用仍在执行,尚未完成对元数据的修改。
•调用sigterm处理程序。
•sigterm handler使用syslog()记录日志消息,然后释放log message变量。
此时,堆的状态不确定,因为malloc仍在修改堆的元数据;元数据可能处于不一致的状态。对free()的sigterm处理程序调用假定元数据不一致,可能导致它在管理堆时将数据写入错误的位置。结果导致内存损坏,这可能导致崩溃,甚至代码执行,具体取决于代码运行的环境。
请注意,这是对Michal Zalewski[Ref-360]最初提出的经典示例的改编;原始示例显示可用于代码执行。
还要注意,这是对Michal Zalewski[Ref-360]最初提出的经典示例的改编;原始示例显示可用于代码执行。
例2
下面的代码用多个信号注册一个信号处理程序,以便在特定事件发生时进行日志记录,并在退出前释放关联的内存。
(问题代码)
Example Language: C
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
void *global1, *global2;
char *what;
void sh (int dummy) {
syslog(LOG_NOTICE,"%s\n",what);
free(global2);
free(global1);
/* Sleep statements added to expand timing window for race condition */
sleep(10);
exit(0);
}
int main (int argc,char* argv[]) {
what=argv[1];
global1=strdup(argv[2]);
global2=malloc(340);
signal(SIGHUP,sh);
signal(SIGTERM,sh);
/* Sleep statements added to expand timing window for race condition */
sleep(10);
exit(0);
}
- 但是,以下事件序列可能导致双重自由(CWE-415):
- 向流程发送叹息
- .调用sh()来处理叹息
- .第一次调用sh()到达释放global1的点
- .此时,向进程发送一个sigterm
- 第二次调用sh()可能会再次释放global1
- 这导致双自由(CWE-415)
这只是对上述代码的一种可能的利用。另一个例子是,syslog调用可能使用不异步信号安全的malloc调用。这可能导致堆管理结构的损坏。有关更多详细信息,请参阅“为乐趣和利润传递信号”中的示例[Ref-360]。
应对措施
阶段: 需求 策略: 语言选择 使用不允许出现这种弱点的语言,或提供使这种弱点更容易避免的结构。 |
阶段: 架构与设计 将信号处理程序设计为只设置标志,而不是执行复杂的功能。然后可以在主程序循环中检查和操作这些标志。 |
阶段: 实现 只在信号处理程序中使用可重入函数。此外,在执行影响执行状态的异步操作时,使用健全性检查确保状态一致。 |
种属
关系 | 类型 | ID | 名称 |
属于 | 361 | ||
属于 | 884 | ||
属于 | 986 |
说明
研究空白
可能仍然在研究。