理解竞争条件( Race condition)漏洞
这几天一个叫做"Dirty COW"的linux内核竞争条件漏洞蛮火的,相关公司不但给这个漏洞起了个洋气的名字,还给它设计了logo(见下图),首页,Twitter账号以及网店。恰逢周末,闲来无事的我也强势围观了一波,在这之前,好好的学习了一下竞争条件以及看了一下近几年关于竞争条件漏洞。
1:什么是竞争条件以及竞争条件为什么会产生漏洞
竞争条件是系统中的一种反常现象,由于现代Linux系统中大量使用并发编程,对资源进行共享,如果产生错误的访问模式,便可能产生内存泄露,系统崩溃,数据破坏,甚至安全问题。竞争条件漏洞就是多个进程访问同一资源时产生的时间或者序列的冲突,并利用这个冲突来对系统进行攻击。一个看起来无害的程序如果被恶意攻击者利用,将发生竞争条件漏洞。
用简单代码讲的更清楚:
//myThreadTest
#include <stdio.h>
#include <pthread.h>
#include <unistd.h> int i = ;
void *mythread1()
{
if(i == ){ <a>
sleep();
if(i == ) <b>
printf("hack it!\n"); else
printf("you can try again!\n");
}
}
void *mythread2()
{
sleep();
i=;
} int main(int argc, const char *argv[])
{
pthread_t id1,id2; pthread_create(&id1, NULL, (void *)mythread1,NULL);
pthread_create(&id2, NULL, (void *)mythread2,NULL); pthread_join(id1,NULL);
pthread_join(id2,NULL); return ;
}
单独看mythread1()函数,显然肯定是输出 "you can try again!\n",但是,由于i是全局共享的资源可以通过线程的方式来使i值在<a>的之后<b>之前进行改变,可以改变函数的流程
为了使结果清晰明了,所以手动利用sleep()函数进行设置了,实际利用过程中,可能是一些会耗时较长的函数,如memcpy()
流程如下:
这也是竞争条件的核心思想,这也是一个数据竞争引发条件竞争的典型例子。
2:以cve-2014-0496为例
由于Android的崛起起,Linux内核的安全性受到了极大地考验,很多潜藏的安全也慢慢被安全研究眼发现。这个漏洞的主要成因是因为在pty/tty设备驱动中在访问某些资源的时候没有正确的加锁处理,准确来说,加锁的范围较小。首先,先看一下理解这个漏洞必要的两个数据结构
struct tty_buffer {
struct tty_buffer *next;
char *char_buf_ptr;
unsigned char *flag_buf_ptr;
int used;
int size;
int commit;
int read;
/* Data points here */
unsigned long data[];
}; struct tty_struct {
int magic;
struct kref kref;
struct device *dev;
struct tty_driver *driver;
const struct tty_operations *ops;
struct tty_bufhead buf; };
tty_buffer是一个动态大小的数据结构,其中,char_buf_ptr指向该对象后面的第一字节,即(char_buf_ptr = tty_buffer+sizeof(tty_buffer)大小为size... flag_buf_ptr=tty_buffer+sizeof(tty_buffer)+size。大小为size。used为已经使用的buffer大小。tty_struct为tty的数据结构,其中ops为tty设备的一些操作函数,如open(),write()。
该漏洞的函数调用为write(pty_fd) in userspace -> sys_write() in kernelspace -> tty_write() -> pty_write() -> tty_insert_flip_string_fixed_flag()。看 tty_insert_flip_string_fixed_flag()函数:
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
const unsigned char *chars, char flag, size_t size)
{
int copied = ;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(tty, goal);
struct tty_buffer *tb = tty->buf.tail;
if (unlikely(space == ))
break;
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
copied += space;
chars += space;
} while (unlikely(size > copied));
return copied;
}
这个函数的大致流程为通过tty_buffer_request_room来申请函数空间,如果没有,则另外申请。利用memcpy进行复制内存。最后再递增used。其中memcpy调用时间较长,由于没有加锁,存在竞争条件的问题,查看tty_buffer_request_room,看是否能够利用:
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
int left;
unsigned long flags; spin_lock_irqsave(&tty->buf.lock, flags); if ((b = tty->buf.tail) != NULL)
left = b->size - b->used;
else
left = 0;
if (left < size) { <1>
/* This is the slow path - looking for new buffers to use */
if ((n = tty_buffer_find(tty, size)) != NULL) {
if (b != NULL) {
b->next = n;
b->commit = b->used;
} else
tty->buf.head = n;
tty->buf.tail = n;
} else
size = left;
}
spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
这里有一个整数溢出的问题,由于程序员的疏忽size为unsigned,而left为int,根据c语言规则,left为转化为无符号,在<1>中,如果left为负数,转化为无符号数,便可以实现size大于left,即需要的空间大于空余的空间,但是仍不进行内存分配,再通过tty_insert_flip_string_fixed_flag函数里的memcpy来溢出,对内存进行读写。left = b->size - b->used,其中size不能改变,但是可以改变used的值,通过条件竞争,来对used进行连续多次写,使used大于size。
详细流程图如下:
由于memcpy函数将会持续较长时间,只要对一个tty连续多次利用多线程对该函数进行申请空间,使used > size,这样就可以在使用memcpy时,进行内存溢出。
这个漏洞,是一个非常典型的竞争条件漏洞。其实也就是上面那个测试代码也是这个函数的简化版。
3:结语
在现代操作系统,竞争条件是不可避免的,只要两个两个执行线程访问同一个数据结构,由于我们无法预测linux调度的顺序,就会产生混合,就可能产竞争条件。我们如果需要对内核或驱动编写,应该尽量避免资源的共享,如果不可避免,需要利用锁来对原子数据进行锁定。
理解竞争条件( Race condition)漏洞的更多相关文章
- 竞态条件 race condition data race
竞态条件 race condition Race condition - Wikipedia https://en.wikipedia.org/wiki/Race_condition A race c ...
- Golang 入门 : 竞争条件
笔者在前文<Golang 入门 : 理解并发与并行>和<Golang 入门 : goroutine(协程)>中介绍了 Golang 对并发的原生支持以及 goroutine 的 ...
- Fortify Audit Workbench 笔记 Race Condition: Singleton Member Field 竞争条件:单例的成员字段
Race Condition: Singleton Member Field 竞争条件:单例的成员字段 Abstract Servlet 成员字段可能允许一个用户查看其他用户的数据. Explanat ...
- Operating System-进程/线程内部通信-竞争条件(Race Conditions)
从本文开始介绍进程间的通信,进程间通信遇到的问题以及方式其实和线程之间通信是一致的,所以进程间通信的所有理论知识都可以用在线程上,接下来的系列文章都会以进程之间的通信为模版进行介绍,本文主要内容: 进 ...
- WEB安全新玩法 [10] 防范竞争条件支付漏洞
服务器端业务逻辑,特别是涉及数据库读写时,存在着关键步骤的时序问题,如果设计或代码编写不当就可能存在竞争条件漏洞.攻击者可以利用多线程并发技术,在数据库的余额字段更新之前,同时发起多次兑换积分或购买商 ...
- 理解 Linux 条件变量
理解 Linux 条件变量 1 简介 当多个线程之间因为存在某种依赖关系,导致只有当某个条件存在时,才可以执行某个线程,此时条件变量(pthread_cond_t)可以派上用场.比如: 例1: 当系统 ...
- Race condition
在很多门课上都接触到race condition, 其中也举了很多方法解决这个问题.于是想来总结一下这些方法. Race condition 它旨在描述一个系统或者进程的输出依赖于不受控制的事件出现顺 ...
- 【多线程同步案例】Race Condition引起的性能问题
Race Condition(也叫做资源竞争),是多线程编程中比较头疼的问题.特别是Java多线程模型当中,经常会因为多个线程同时访问相同的共享数据,而造成数据的不一致性.为了解决这个问题,通常来说需 ...
- python线程条件变量Condition(31)
对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 一.线程条件变 ...
随机推荐
- 我给女朋友讲编程CSS系列(4) CSS盒子模型
什么是CSS盒子模型?如何学习CSS的盒子模型? 这篇文章,以 [分享 + 结论] 的方式来写. 1, 看w3school的[CSS 框模型概述] 网址为: http://www.w3school ...
- An internal error occurred during: "Launching on Tomcat 7.x"
1.首先关闭MyEclipse工作空间.2.然后删除工作空间下的文件.“MyEclipse10\workspace.metadata.plugins\org.eclipse.core.runtime. ...
- 关于MySQL查询优化 の 30条忠告
撸自:http://www.jincon.com/archives/120/ 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避 ...
- Hastable和Dictionary以及ArrayList和(List,LinkedList,数组)的区别
Hastable和Dictionary的区别:(键值对) 1:单线程程序中推荐使用 Dictionary, 有泛型优势, 且读取速度较快, 容量利用更充分. 2:多线程程序中推荐使用 Hashtabl ...
- (原)Unreal渲染相关的缓冲区 及其 自定义代码几种抓取
@authot: 白袍小道 转载说明那啥即可. (图片和本文无关,嘿嘿,坑一下) 以下为Unreal4.18版本中对GPUBuffer部分的分析结果 (插入:比之够着,知至目的) ...
- sources-t.list
deb http://debian.ustc.edu.cn/ubuntu/ trusty main multiverse restricted universe deb http://debian.u ...
- 原始套接字--traceroute
traceroute, 也就是 trace route,跟踪路由.这个程序最早是Van Jacobson实现的.源码在网上可以找到,不过我还没有去找.是IP路由过程中对数据包TTL(Time to L ...
- ftrace 简介
ftrace 简介 ftrace 的作用是帮助开发人员了解 Linux 内核的运行时行为,以便进行故障调试或性能分析. 最早 ftrace 是一个 function tracer,仅能够记录内核的函数 ...
- ubuntu16.04 搭建nexus+maven 学习
/opt/nexus-2.10.0-02/bin vim nexus 关键配置: RUN_AS_USER=root JAVA_HOME=/usr/lib/java/jre export NEXUS_H ...
- 怎么用tomcat对socket接口的程序进行调试
对socket(套接字)的demo方法大多都是用main方法进行测试的,那如何用tomcat进行测试呢? 这里需要借助一个工具:工具的名字是:Sockettool.exe .下图是该工具的内容.连上监 ...