博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CVE-2019-11815内核竞态漏洞推测
阅读量:2343 次
发布时间:2019-05-10

本文共 4270 字,大约阅读时间需要 14 分钟。

这个本来想看下利用过程,奈何没找到poc. 感觉自己其实也懂不少原理了,来推测下吧。

https://www.freebuf.com/vuls/208256.html

补丁位置

根据官网漏洞信息,可以知道此漏洞大概是个uaf之类的漏洞。

static void rds_tcp_kill_sock(struct net *net){
struct rds_tcp_connection *tc, *_tc; LIST_HEAD(tmp_list); struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid); struct socket *lsock = rtn->rds_tcp_listen_sock; rtn->rds_tcp_listen_sock = NULL; rds_tcp_listen_stop(lsock, &rtn->rds_tcp_accept_w); spin_lock_irq(&rds_tcp_conn_lock); list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); if (net != c_net || !tc->t_sock) continue; if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn)) {
list_move_tail(&tc->t_tcp_node, &tmp_list); } else {
list_del(&tc->t_tcp_node); tc->t_tcp_node_detached = true; } } spin_unlock_irq(&rds_tcp_conn_lock); list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) rds_conn_destroy(tc->t_cpath->cp_conn);}
diff --git a/net/rds/tcp.c b/net/rds/tcp.cindex fd26941..faf726e 100644--- a/net/rds/tcp.c+++ b/net/rds/tcp.c@@ -608,7 +608,7 @@ static void rds_tcp_kill_sock(struct net *net) 	list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); - if (net != c_net || !tc->t_sock)+ if (net != c_net) continue; if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn)) {
list_move_tail(&tc->t_tcp_node, &tmp_list);

可以看到在某个if语句中删掉了tc->t_socket这个指针的判断。也就是说,漏洞是触发了t_sock不为空的状态,是函数执行到了list_move_tail的list添加tmp_list过程。我们看到之后会对这个list进行rds_conn_destroy。

漏洞细节推测

到了destroy这里,其实已经比较明确了。uaf的利用过程是对释放后没有清空的堆栈进行二次利用的手段,那么我可以比较肯定的推测这个tc->t_cpath->cp_conn里面肯定有一个函数指针没有清空,导致了内存被占用后的利用。

其定义为:

/* One rds_connection per RDS address pair */struct rds_connection {
struct hlist_node c_hash_node; struct in6_addr c_laddr; struct in6_addr c_faddr; int c_dev_if; /* ifindex used for this conn */ int c_bound_if; /* ifindex of c_laddr */ unsigned int c_loopback:1, c_isv6:1, c_ping_triggered:1, c_pad_to_32:29; int c_npaths; struct rds_connection *c_passive; struct rds_transport *c_trans; struct rds_cong_map *c_lcong; struct rds_cong_map *c_fcong; /* Protocol version */ unsigned int c_version; possible_net_t c_net; struct list_head c_map_item; unsigned long c_map_queued; struct rds_conn_path *c_path; wait_queue_head_t c_hs_waitq; /* handshake waitq */ u32 c_my_gen_num; u32 c_peer_gen_num;};

翻看源代码rd_connectioin没有可利用的指正,rds_connect_path 可能有但没看,估计会麻烦一点。这里rds_trransport的struct被发现,可能有利用点,查看下。

struct rds_transport {
char t_name[TRANSNAMSIZ]; struct list_head t_item; struct module *t_owner; unsigned int t_prefer_loopback:1, t_mp_capable:1; unsigned int t_type; int (*laddr_check)(struct net *net, const struct in6_addr *addr, __u32 scope_id); int (*conn_alloc)(struct rds_connection *conn, gfp_t gfp); void (*conn_free)(void *data); int (*conn_path_connect)(struct rds_conn_path *cp); void (*conn_path_shutdown)(struct rds_conn_path *conn); void (*xmit_path_prepare)(struct rds_conn_path *cp); void (*xmit_path_complete)(struct rds_conn_path *cp); int (*xmit)(struct rds_connection *conn, struct rds_message *rm, unsigned int hdr_off, unsigned int sg, unsigned int off); int (*xmit_rdma)(struct rds_connection *conn, struct rm_rdma_op *op); int (*xmit_atomic)(struct rds_connection *conn, struct rm_atomic_op *op); int (*recv_path)(struct rds_conn_path *cp); int (*inc_copy_to_user)(struct rds_incoming *inc, struct iov_iter *to); void (*inc_free)(struct rds_incoming *inc); int (*cm_handle_connect)(struct rdma_cm_id *cm_id, struct rdma_cm_event *event, bool isv6); int (*cm_initiate_connect)(struct rdma_cm_id *cm_id, bool isv6); void (*cm_connect_complete)(struct rds_connection *conn, struct rdma_cm_event *event); unsigned int (*stats_info_copy)(struct rds_info_iterator *iter, unsigned int avail); void (*exit)(void); void *(*get_mr)(struct scatterlist *sg, unsigned long nr_sg, struct rds_sock *rs, u32 *key_ret, struct rds_connection *conn); void (*sync_mr)(void *trans_private, int direction); void (*free_mr)(void *trans_private, int invalidate); void (*flush_mrs)(void); bool (*t_unloading)(struct rds_connection *conn);};

果然,里面有大片的指针函数。只要任意覆盖一个,就可以出发崩溃,代码执行可能复杂点,但理论赶上也可以。

转载地址:http://pnjvb.baihongyu.com/

你可能感兴趣的文章
数组名和指针的区别
查看>>
栈和堆的具体区别
查看>>
如何判断一个点在矩形内
查看>>
析构函数何时被调用
查看>>
C++虚函数底层机制
查看>>
面试题:随机数生成、蓄水池抽样、海量数据、设计秒杀系统
查看>>
linux清除cache的方法
查看>>
memmove 和 memcpy的区别以及处理内存重叠问题
查看>>
费雪耶兹(Fisher–Yates) 也被称作高纳德( Knuth)随机置乱算法
查看>>
C/C++中变量的存储位置
查看>>
C++中四种强制类型转换区别详解
查看>>
linux gdb的详细用法 运行与断点
查看>>
删除vector中重复元素
查看>>
和为s的连续正数序列
查看>>
什么是Redis?什么是nosql?NoSQL数据库的四大分类
查看>>
为什么说Redis是单线程的以及Redis为什么这么快!
查看>>
redis的过期健删除策略以及内存淘汰机制
查看>>
map 如何使用结构体作为自定义键值
查看>>
Mysql几种索引类型的区别及适用情况
查看>>
Redis持久化的两种方式
查看>>