todo: mas_msg和pipe_buffer在ctf/linux kernel漏洞利用的实际应用。
之前提到,在正常的linux kernel环境下,堆风水布局是十分困难的。主要原因是内核大都使用kmalloc来申请内存,有漏洞的驱动大概率也是用kmalloc申请的内存。
但是msg_msg和pipe_buffer给我们提供了一个有效的进行堆布局的方法.
1. msg_msg
msg_msg是linux提供的一种进程间通信(IPC)的结构体。
1.1 msg常见用法
msg在linux本质上是通过内核消息队列来进行通信的。
主要函数如下:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
可以看一下demo:
//msg_send.c 用于发送msg
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <stdio.h>
int main(){
// prepare message
size_t target_cache_size = 128;
struct msgbuf{
long mtype;
char message[100];
};
size_t msg_sz = target_cache_size-0x30;
struct msgbuf msgbuf;
strcpy(msgbuf.message,"hello world!");
puts("before creating messages");
getchar();
int msqid;
int key = ftok(".",0);
msqid = msgget(key,0666| IPC_CREAT);
for(int i=0;i<20;i++){
msgbuf.mtype = i+1;//注意mtype不能为0,0会出问题。
msgsnd(msqid,&msgbuf,msg_sz,0);
}
puts("after creating messages");
getchar();
}
//msg_recv.c 用于接收msg
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <stdio.h>
int main(){
// prepare message
size_t target_cache_size = 128;
struct msgbuf{
long mtype;
char message[100];
};
size_t msg_sz = target_cache_size-0x30;
struct msgbuf msgbuf;
strcpy(msgbuf.message,"hello world!");
puts("before creating messages");
getchar();
int msqid;
int key = ftok(".",0);
msqid = msgget(key,0666);
for(int i=0;i<20;i++){
msgrcv(msqid,&msgbuf,msg_sz,0,0);
printf("received with type: %d, content: %s\n",msgbuf.mtype,msgbuf.message);
}
puts("after creating messages");
getchar();
}

1.2 为什么要介绍msg?
还记得上一节https://wsxk.github.io/kernel_heap2/中提到的理想的堆布局构造对象吗?
首先看内核中msg_msg对象的定义:
/* one msg_msg structure for each message */
struct msg_msg {
struct list_head m_list;
long m_type;
size_t m_ts; /* message text size */
struct msg_msgseg *next; //****完美满足第3点!ptr可覆盖!****
void *security;
/* the actual message follows immediately */
};
//m_list contains pointers to messages in the message queue
//m_ts determines this size of the message text
我们接下来看一下msg_msg是如何分配的:
static struct msg_msg *alloc_msg(size_t len)
{
struct msg_msg *msg;
struct msg_msgseg **pseg;
size_t alen;
alen = min(len, DATALEN_MSG);
msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);//0x28+8(mtype)+实际消息长度
//****完美满足第一点!size可控!!!****
}
在调用msgrcv函数时,发生如下事件:
struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) {
struct msg_msgseg *dst_pseg, *src_pseg;
size_t len = src->m_ts;
size_t alen;
if (src->m_ts > dst->m_ts)
return ERR_PTR(-EINVAL);
alen = min(len, DATALEN_MSG);
memcpy(dst + 1, src + 1, alen);//****完美满足第二点!绕过harden_usercopy!!!****
}
//copy_msg can be triggered via msgrcv(msgqid, msgp, msgsz, 0, MSG_COPY);
2. pipe_buffer
2.1 pipe_buffer 常见用法
pipe_buffer也是内核IPC通信的方法之一,通过管道pipe来进行通信;
2.2 为什么要介绍pipe_buffer?
pipe_buffer的定义如下:
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;//包含函数指针,越界写即可完成控制流劫持!
unsigned int flags;
unsigned long private;
};
3. 具体案例
todo,等到复现linux cve的时候应该就用上了