CVE-2019-11815内核竞态漏洞推测

这个本来想看下利用过程,奈何没找到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.c
index 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);
};

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值