{"id":720,"date":"2020-09-11T07:35:44","date_gmt":"2020-09-11T05:35:44","guid":{"rendered":"http:\/\/blog.pi3.com.pl\/?p=720"},"modified":"2020-09-11T07:35:44","modified_gmt":"2020-09-11T05:35:44","slug":"cve-2020-14356-2020-25220","status":"publish","type":"post","link":"https:\/\/blog.pi3.com.pl\/?p=720","title":{"rendered":"CVE: 2020-14356 &#038; 2020-25220"},"content":{"rendered":"\n<p class=\"has-medium-font-size\"><strong><span style=\"text-decoration: underline;\" class=\"underline\">The short story of 1 Linux Kernel Use-After-Free bug and 2 CVEs (CVE-2020-14356 and CVE-2020-25220)<\/span><\/strong><\/p>\n\n\n\n<p>Name:&nbsp;&nbsp;&nbsp;&nbsp; Linux kernel Cgroup BPF Use-After-Free<br>Author:&nbsp;&nbsp; Adam Zabrocki (<a href=\"mailto:pi3@pi3.com.pl\">pi3@pi3.com.pl<\/a>)<br>Date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; May 27, 2020<\/p>\n\n\n\n<!--more-->\n\n\n\n<p><span style=\"font-size: 14pt;\"><strong><span style=\"text-decoration: underline;\">First things first &#8211; short history:<\/span><\/strong><\/span><\/p>\n\n\n\n<p>In 2019 Tejun Heo discovered a racing problem with lifetime of the cgroup_bpf which could result in double-free and other memory corruptions. This bug was fixed in kernel 5.3. More information about the problem and the patch can be found here:<\/p>\n\n\n\n<p><a href=\"https:\/\/lore.kernel.org\/patchwork\/patch\/1094080\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/lore.kernel.org\/patchwork\/patch\/1094080\/<\/a><\/p>\n\n\n\n<p>Roman Gushchin discovered another problem with the newly fixed code which could lead to use-after-free vulnerability. His report and fix can be found here:<\/p>\n\n\n\n<p><a href=\"https:\/\/lore.kernel.org\/bpf\/20191227215034.3169624-1-guro@fb.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/lore.kernel.org\/bpf\/20191227215034.3169624-1-guro@fb.com\/<\/a><\/p>\n\n\n\n<p>During the discussion on the fix, Alexei Starovoitov pointed out that walking through the cgroup hierarchy without holding cgroup_mutex might be dangerous:<\/p>\n\n\n\n<p><a href=\"https:\/\/lore.kernel.org\/bpf\/20200104003523.rfte5rw6hbnncjes@ast-mbp\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/lore.kernel.org\/bpf\/20200104003523.rfte5rw6hbnncjes@ast-mbp\/<\/a><\/p>\n\n\n\n<p>However, Roman and Alexei concluded that it shouldn&#8217;t be a problem:<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/lore.kernel.org\/bpf\/20200106220746.fm3hp3zynaiaqgly@ast-mbp\/\" target=\"_blank\">https:\/\/lore.kernel.org\/bpf\/20200106220746.fm3hp3zynaiaqgly@ast-mbp\/<\/a><\/p>\n\n\n\n<p>Unfortunately, there is another Use-After-Free bug related to the Cgroup BPF release logic.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong><span style=\"text-decoration: underline\" class=\"underline\">The &#8220;new&#8221; bug &#8211; details (a lot of details ;-)):<\/span><\/strong><\/p>\n\n\n\n<p>During LKRG development and tests, one of my VMs was generating a kernel crash during shutdown procedure. This specific machine had the newest kernel at that time (5.7.x) and I compiled it with all debug information as well as SLAB DEBUG feature. When I analyzed the crash, it had nothing to do with LKRG. Later I confirmed that kernels without LKRG are always hitting that issue:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      KERNEL: linux-5.7\/vmlinux\n    DUMPFILE: \/var\/crash\/202006161848\/dump.202006161848  &#91;PARTIAL DUMP]\n        CPUS: 1\n        DATE: Tue Jun 16 18:47:40 2020\n      UPTIME: 14:09:24\nLOAD AVERAGE: 0.21, 0.37, 0.50\n       TASKS: 234\n    NODENAME: oi3\n     RELEASE: 5.7.0-g4\n     VERSION: #28 SMP PREEMPT Fri Jun 12 18:09:14 UTC 2020\n     MACHINE: x86_64  (3694 Mhz)\n      MEMORY: 8 GB\n       PANIC: \"Oops: 0000 &#91;#1] PREEMPT SMP PTI\" (check log for details)\n         PID: 1060499\n     COMMAND: \"sshd\"\n        TASK: ffff9d8c36b33040  &#91;THREAD_INFO: ffff9d8c36b33040]\n         CPU: 0\n       STATE:  (PANIC)\n\ncrash> bt\nPID: 1060499  TASK: ffff9d8c36b33040  CPU: 0   COMMAND: \"sshd\"\n #0 &#91;ffffb0fc41b1f990] machine_kexec at ffffffff9404d22f\n #1 &#91;ffffb0fc41b1f9d8] __crash_kexec at ffffffff941c19b8\n #2 &#91;ffffb0fc41b1faa0] crash_kexec at ffffffff941c2b60\n #3 &#91;ffffb0fc41b1fab0] oops_end at ffffffff94019d3e\n #4 &#91;ffffb0fc41b1fad0] page_fault at ffffffff95c0104f\n    &#91;exception RIP: __cgroup_bpf_run_filter_skb+401]\n    RIP: ffffffff9423e801  RSP: ffffb0fc41b1fb88  RFLAGS: 00010246\n    RAX: 0000000000000000  RBX: ffff9d8d56ae1ee0  RCX: 0000000000000028\n    RDX: 0000000000000000  RSI: ffff9d8e25c40b00  RDI: ffffffff9423e7f3\n    RBP: 0000000000000000   R8: 0000000000000000   R9: 0000000000000000\n    R10: 0000000000000003  R11: 0000000000000000  R12: 0000000000000000\n    R13: 0000000000000000  R14: 0000000000000000  R15: 0000000000000001\n    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018\n #5 &#91;ffffb0fc41b1fbd0] ip_finish_output at ffffffff957d71b3\n #6 &#91;ffffb0fc41b1fbf8] __ip_queue_xmit at ffffffff957d84e1\n #7 &#91;ffffb0fc41b1fc50] __tcp_transmit_skb at ffffffff957f4b27\n #8 &#91;ffffb0fc41b1fd58] tcp_write_xmit at ffffffff957f6579\n #9 &#91;ffffb0fc41b1fdb8] __tcp_push_pending_frames at ffffffff957f737d\n#10 &#91;ffffb0fc41b1fdd0] tcp_close at ffffffff957e6ec1\n#11 &#91;ffffb0fc41b1fdf8] inet_release at ffffffff9581809f\n#12 &#91;ffffb0fc41b1fe10] __sock_release at ffffffff95616848\n#13 &#91;ffffb0fc41b1fe30] sock_close at ffffffff956168bc\n#14 &#91;ffffb0fc41b1fe38] __fput at ffffffff942fd3cd\n#15 &#91;ffffb0fc41b1fe78] task_work_run at ffffffff94148a4a\n#16 &#91;ffffb0fc41b1fe98] do_exit at ffffffff9412b144\n#17 &#91;ffffb0fc41b1ff08] do_group_exit at ffffffff9412b8ae\n#18 &#91;ffffb0fc41b1ff30] __x64_sys_exit_group at ffffffff9412b92f\n#19 &#91;ffffb0fc41b1ff38] do_syscall_64 at ffffffff940028d7\n#20 &#91;ffffb0fc41b1ff50] entry_SYSCALL_64_after_hwframe at ffffffff95c0007c\n    RIP: 00007fe54ea30136  RSP: 00007fff33413468  RFLAGS: 00000202\n    RAX: ffffffffffffffda  RBX: 00007fff334134e0  RCX: 00007fe54ea30136\n    RDX: 00000000000000ff  RSI: 000000000000003c  RDI: 00000000000000ff\n    RBP: 00000000000000ff   R8: 00000000000000e7   R9: fffffffffffffdf0\n    R10: 000055a091a22d09  R11: 0000000000000202  R12: 000055a091d67f20\n    R13: 00007fe54ea5afa0  R14: 000055a091d7ef70  R15: 000055a091d70a20\n    ORIG_RAX: 00000000000000e7  CS: 0033  SS: 002b<\/code><\/pre>\n\n\n\n<p><strong>1060499 <\/strong>is a sshd&#8217;s child:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">...\r\nroot        5462  0.0  0.0  12168  7276 ?        Ss   04:38   0:00 sshd: \/usr\/sbin\/sshd -D [listener] 0 of 10-100 startups\r\n...\r\nroot     1060499  0.0  0.1  13936  9056 ?        Ss   17:51   0:00  \\_ sshd: pi3 [priv]\r\npi3      1062463  0.0  0.0  13936  5852 ?        S    17:51   0:00      \\_ sshd: pi3@pts\/3\r\n...<\/span><\/span><\/span><\/code><\/pre>\n\n\n\n<p>Crash happens in function &#8220;__cgroup_bpf_run_filter_skb&#8221;, exactly in this piece of code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><span style=\"font-size: 4pt;\"><code><span style=\"font-family: andale mono, monospace;\"><span style=\"font-family: courier new, courier, monospace; font-size: 8pt;\">0xffffffff9423e7ee &lt;__cgroup_bpf_run_filter_skb+382&gt;: callq  0xffffffff94153cb0 &lt;preempt_count_add&gt;\n0xffffffff9423e7f3 &lt;__cgroup_bpf_run_filter_skb+387&gt;: callq  0xffffffff941925a0 &lt;__rcu_read_lock&gt;\n0xffffffff9423e7f8 &lt;__cgroup_bpf_run_filter_skb+392&gt;: mov 0x3e8(%rbp),%rax\n0xffffffff9423e7ff &lt;__cgroup_bpf_run_filter_skb+399&gt;: xor %ebp,%ebp\n0xffffffff9423e801 &lt;__cgroup_bpf_run_filter_skb+401&gt;: mov 0x10(%rax),%rdi\n                                                          ^^^^^^^^^^^^^^^\n0xffffffff9423e805 &lt;__cgroup_bpf_run_filter_skb+405&gt;: lea 0x10(%rax),%r14\n0xffffffff9423e809 &lt;__cgroup_bpf_run_filter_skb+409&gt;: test %rdi,%rdi<\/span><\/span><\/code><\/span><\/pre>\n\n\n\n<p>where RAX: 0000000000000000. However, when I was playing with repro under SLAB_DEBUG, I often got RAX: 6b6b6b6b6b6b6b6b:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    &#91;exception RIP: __cgroup_bpf_run_filter_skb+401]\n    RIP: ffffffff9123e801  RSP: ffffb136c16ffb88  RFLAGS: 00010246\n    RAX: 6b6b6b6b6b6b6b6b  RBX: ffff9ce3e5a0e0e0  RCX: 0000000000000028\n    RDX: 0000000000000000  RSI: ffff9ce3de26b280  RDI: ffffffff9123e7f3\n    RBP: 0000000000000000   R8: 0000000000000000   R9: 0000000000000000\n    R10: 0000000000000003  R11: 0000000000000000  R12: 0000000000000000\n    R13: 0000000000000000  R14: 0000000000000000  R15: 0000000000000001<\/code><\/pre>\n\n\n\n<p>So we have kind of a Use-After-Free bug. This bug is triggerable from user-mode. I&#8217;ve looked under IDA for the binary:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.text:FFFFFFFF8123E7EE skb = rbx      ; sk_buff * ; PIC mode\n.text:FFFFFFFF8123E7EE type = r15     ; bpf_attach_type\n.text:FFFFFFFF8123E7EE save_sk = rsi  ; sock *\n.text:FFFFFFFF8123E7EE        call    near ptr preempt_count_add-0EAB43h\n.text:FFFFFFFF8123E7F3        call    near ptr __rcu_read_lock-0AC258h ; PIC mode\n.text:FFFFFFFF8123E7F8        mov     ret, &#91;rbp+3E8h]\n.text:FFFFFFFF8123E7FF        xor     ebp, ebp\n.text:FFFFFFFF8123E801 _cn = rbp      ; u32\n.text:FFFFFFFF8123E801        mov     rdi, &#91;ret+10h]  ; prog\n.text:FFFFFFFF8123E805        lea     r14, &#91;ret+10h]<\/code><\/pre>\n\n\n\n<p>and this code is referencing cgroups from the socket. Source code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">int __cgroup_bpf_run_filter_skb(struct sock *sk,\n\t\t\t\tstruct sk_buff *skb,\n\t\t\t\tenum bpf_attach_type type)\n{\n    ...\n\tstruct cgroup *cgrp;\n    ...<br><span style=\"font-size: 10pt;\"><span style=\"font-size: 8pt;\">\n    ...\n\tcgrp = sock_cgroup_ptr(&amp;sk-&gt;sk_cgrp_data);\n    ...\n\tif (type == BPF_CGROUP_INET_EGRESS) {\n\t\tret = BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY(\n\t\t\tcgrp-&gt;bpf.effective[type], skb, __bpf_prog_run_save_cb);\n    ...\n    ...\n}<\/span><\/span><\/span><\/code><\/pre>\n\n\n\n<p>Debugger:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>crash> x\/4i 0xffffffff9423e7f8\n   0xffffffff9423e7f8:  mov    0x3e8(%rbp),%rax\n   0xffffffff9423e7ff:  xor    %ebp,%ebp\n   0xffffffff9423e801:  mov    0x10(%rax),%rdi\n   0xffffffff9423e805:  lea    0x10(%rax),%r14\ncrash> p\/x (int)&amp;((struct cgroup*)0)->bpf\n$2 = 0x3e0\ncrash> ptype struct cgroup_bpf\ntype = struct cgroup_bpf {\n    struct bpf_prog_array *effective&#91;28];\n    struct list_head progs&#91;28];\n    u32 flags&#91;28];\n    struct bpf_prog_array *inactive;\n    struct percpu_ref refcnt;\n    struct work_struct release_work;\n}\ncrash> print\/a sizeof(struct bpf_prog_array)\n$3 = 0x10\ncrash> print\/a ((struct sk_buff *)0xffff9ce3e5a0e0e0)->sk\n$4 = 0xffff9ce3de26b280\ncrash> print\/a ((struct sock *)0xffff9ce3de26b280)->sk_cgrp_data\n$5 = {\n  {\n    {\n      is_data = 0x0,\n      padding = 0x68,\n      prioidx = 0xe241,\n      classid = 0xffff9ce3\n    },\n    val = 0xffff9ce3e2416800\n  }\n}<\/code><\/pre>\n\n\n\n<p>We also know that R15: 0000000000000001 == type == BPF_CGROUP_INET_EGRESS<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>crash> p\/a ((struct cgroup *)0xffff9ce3e2416800)->bpf.effective&#91;1]\n$6 = 0x6b6b6b6b6b6b6b6b\ncrash> x\/20a 0xffff9ce3e2416800\n0xffff9ce3e2416800:     0x6b6b6b6b6b6b016b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416810:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416820:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416830:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416840:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416850:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416860:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416870:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416880:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\n0xffff9ce3e2416890:     0x6b6b6b6b6b6b6b6b      0x6b6b6b6b6b6b6b6b\ncrash><\/code><\/pre>\n\n\n\n<p>This pointer (struct cgroup *)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tcgrp = sock_cgroup_ptr(&amp;sk->sk_cgrp_data);<\/code><\/pre>\n\n\n\n<p>Points to the freed object. However, kernel still keeps eBPF rules attached to the socket under cgroups. When process (sshd) dies (do_exit() call) and cleanup is executed, all sockets are being closed. If such socket has &#8220;pending&#8221; packets, the following code path is executed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>do_exit -> ... -> sock_close -> __sock_release -> inet_release -> tcp_close -> __tcp_push_pending_frames -> tcp_write_xmit -> __tcp_transmit_skb -> __ip_queue_xmit -> ip_finish_output -> __cgroup_bpf_run_filter_skb<\/code><\/pre>\n\n\n\n<p>However, there is nothing wrong with such logic and path. The real problem is that cgroups disappeared while still holding active clients. How is that even possible? Just before the crash I can see the following entry in kernel logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">[190820.457422] ------------[ cut here ]------------\n[190820.457465] percpu ref (cgroup_bpf_release_fn) &lt;= 0 (-70581) after switching to atomic\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n[190820.457511] WARNING: CPU: 0 PID: 9 at lib\/percpu-refcount.c:161 percpu_ref_switch_to_atomic_rcu+0x112\/0x120\n[190820.457511] Modules linked in: [last unloaded: p_lkrg]\n[190820.457513] CPU: 0 PID: 9 Comm: ksoftirqd\/0 Kdump: loaded Tainted: G           OE     5.7.0-g4 #28\n[190820.457513] Hardware name: VMware, Inc. VMware Virtual Platform\/440BX Desktop Reference Platform, BIOS 6.00 04\/13\/2018\n[190820.457515] RIP: 0010:percpu_ref_switch_to_atomic_rcu+0x112\/0x120\n[190820.457516] Code: eb b6 80 3d 11 95 5a 02 00 0f 85 65 ff ff ff 48 8b 55 d8 48 8b 75 e8 48 c7 c7 d0 9f 78 93 c6 05 f5 94 5a 02 01 e8 00 57 88 ff &lt;0f&gt; 0b e9 43 ff ff ff 0f 0b eb 9d cc cc cc 8d 8c 16 ef be ad de 89\n[190820.457516] RSP: 0018:ffffb136c0087e00 EFLAGS: 00010286\n[190820.457517] RAX: 0000000000000000 RBX: 7ffffffffffeec4a RCX: 0000000000000000\n[190820.457517] RDX: 0000000000000101 RSI: ffffffff949235c0 RDI: 00000000ffffffff\n[190820.457517] RBP: ffff9ce3e204af20 R08: 6d6f7461206f7420 R09: 63696d6f7461206f\n[190820.457517] R10: 7320726574666120 R11: 676e696863746977 R12: 00003452c5002ce8\n[190820.457518] R13: ffff9ce3f6e2b450 R14: ffff9ce2c7fc3100 R15: 0000000000000000\n[190820.457526] FS:  0000000000000000(0000) GS:ffff9ce3f6e00000(0000) knlGS:0000000000000000\n[190820.457527] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033\n[190820.457527] CR2: 00007f516c2b9000 CR3: 0000000222c64006 CR4: 00000000003606f0\n[190820.457550] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000\n[190820.457551] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400\n[190820.457551] Call Trace:\n[190820.457577]  rcu_core+0x1df\/0x530\n[190820.457598]  ? smpboot_register_percpu_thread+0xd0\/0xd0\n[190820.457609]  __do_softirq+0xfc\/0x331\n[190820.457629]  ? smpboot_register_percpu_thread+0xd0\/0xd0\n[190820.457630]  run_ksoftirqd+0x21\/0x30\n[190820.457649]  smpboot_thread_fn+0x195\/0x230\n[190820.457660]  kthread+0x139\/0x160\n[190820.457670]  ? __kthread_bind_mask+0x60\/0x60\n[190820.457671]  ret_from_fork+0x35\/0x40\n[190820.457682] ---[ end trace 63d2aef89e998452 ]---<\/span><\/code><\/pre>\n\n\n\n<p>I was testing the same scenario a few times and I had the following results:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\"> percpu ref (cgroup_bpf_release_fn) &lt;= 0 (-70581) after switching to atomic\n percpu ref (cgroup_bpf_release_fn) &lt;= 0 (-18829) after switching to atomic\n percpu ref (cgroup_bpf_release_fn) &lt;= 0 (-29849) after switching to atomic\n<\/span><\/code><\/pre>\n\n\n\n<p>Let&#8217;s look at this function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">\/**\n * cgroup_bpf_release_fn() - callback used to schedule releasing\n *                           of bpf cgroup data\n * @ref: percpu ref counter structure\n *\/\nstatic void cgroup_bpf_release_fn(struct percpu_ref *ref)\n{\n\tstruct cgroup *cgrp = container_of(ref, struct cgroup, bpf.refcnt);\n\n\tINIT_WORK(&amp;cgrp-&gt;bpf.release_work, cgroup_bpf_release);\n\tqueue_work(system_wq, &amp;cgrp-&gt;bpf.release_work);\n}<\/span><\/code><\/pre>\n\n\n\n<p>So that&#8217;s the callback used to release bpf cgroup data. Sounds like it is being called while there could be still active socket attached to such cgroup:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">\/**\n * cgroup_bpf_release() - put references of all bpf programs and\n *                        release all cgroup bpf data\n * @work: work structure embedded into the cgroup to modify\n *\/\nstatic void cgroup_bpf_release(struct work_struct *work)\n{\n\tstruct cgroup *p, *cgrp = container_of(work, struct cgroup,\n\t\t\t\t\t       bpf.release_work);\n\tstruct bpf_prog_array *old_array;\n\tunsigned int type;\n\n\tmutex_lock(&amp;cgroup_mutex);\n\n\tfor (type = 0; type &lt; ARRAY_SIZE(cgrp-&gt;bpf.progs); type++) {\n\t\tstruct list_head *progs = &amp;cgrp-&gt;bpf.progs[type];\n\t\tstruct bpf_prog_list *pl, *tmp;\n\n\t\tlist_for_each_entry_safe(pl, tmp, progs, node) {\n\t\t\tlist_del(&amp;pl-&gt;node);\n\t\t\tif (pl-&gt;prog)\n\t\t\t\tbpf_prog_put(pl-&gt;prog);\n\t\t\tif (pl-&gt;link)\n\t\t\t\tbpf_cgroup_link_auto_detach(pl-&gt;link);\n\t\t\tbpf_cgroup_storages_unlink(pl-&gt;storage);\n\t\t\tbpf_cgroup_storages_free(pl-&gt;storage);\n\t\t\tkfree(pl);\n\t\t\tstatic_branch_dec(&amp;cgroup_bpf_enabled_key);\n\t\t}\n\t\told_array = rcu_dereference_protected(\n\t\t\t\tcgrp-&gt;bpf.effective[type],\n\t\t\t\tlockdep_is_held(&amp;cgroup_mutex));\n\t\tbpf_prog_array_free(old_array);\n\t}\n\n\tmutex_unlock(&amp;cgroup_mutex);\n\n\tfor (p = cgroup_parent(cgrp); p; p = cgroup_parent(p))\n\t\tcgroup_bpf_put(p);\n\n\tpercpu_ref_exit(&amp;cgrp-&gt;bpf.refcnt);\n\tcgroup_put(cgrp);\n}<\/span><\/code><\/pre>\n\n\n\n<p>while:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>static void bpf_cgroup_link_auto_detach(struct bpf_cgroup_link *link)\n{\n\tcgroup_put(link->cgroup);\n\tlink->cgroup = NULL;\n}<\/code><\/pre>\n\n\n\n<p>So if cgroup dies, all the potential clients are being auto_detached. However, they might not be aware about such situation. When is cgroup_bpf_release_fn() executed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">\/**\n * cgroup_bpf_inherit() - inherit effective programs from parent\n * @cgrp: the cgroup to modify\n *\/\nint cgroup_bpf_inherit(struct cgroup *cgrp)\n{\n    ...\n  \tret = percpu_ref_init(&amp;cgrp-&gt;bpf.refcnt, cgroup_bpf_release_fn, 0,\n\t\t\t      GFP_KERNEL);\n    ...\n}<\/span><\/code><\/pre>\n\n\n\n<p>It is automatically executed when cgrp-&gt;bpf.refcnt drops to 1. However, in the warning logs before kernel had crashed, we saw that such reference counter is below 0. Cgroup was already freed.<\/p>\n\n\n\n<p>Originally, I thought that the problem might be related to the code walking through the cgroup hierarchy without holding cgroup_mutex, which was pointed out by Alexei. I&#8217;ve prepared the patch and recompiled the kernel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ diff -u cgroup.c linux-5.7\/kernel\/bpf\/cgroup.c\n--- cgroup.c    2020-05-31 23:49:15.000000000 +0000\n+++ linux-5.7\/kernel\/bpf\/cgroup.c       2020-07-17 16:31:10.712969480 +0000\n@@ -126,11 +126,11 @@\n                bpf_prog_array_free(old_array);\n        }\n\n-       mutex_unlock(&amp;cgroup_mutex);\n-\n        for (p = cgroup_parent(cgrp); p; p = cgroup_parent(p))\n                cgroup_bpf_put(p);\n\n+       mutex_unlock(&amp;cgroup_mutex);\n+\n        percpu_ref_exit(&amp;cgrp->bpf.refcnt);\n        cgroup_put(cgrp);\n }<\/code><\/pre>\n\n\n\n<p>Interestingly, without this patch I was able to generate this kernel crash every time when I was rebooting the machine (100% repro). After this patch crashing ratio dropped to around 30%. However, I was still able to hit the same code-path and generate kernel dump. The patch indeed helps but it looks like it&#8217;s not the real problem since I can still hit the crash (just much less often).<\/p>\n\n\n\n<p>I stepped back and looked again where the bug is. Corrupted pointer (struct cgroup *) is comming from that line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tcgrp = sock_cgroup_ptr(&amp;sk->sk_cgrp_data);<\/code><\/pre>\n\n\n\n<p>this code is related to the CONFIG_SOCK_CGROUP_DATA. Linux source has an interesting comment about it in &#8220;cgroup-defs.h&#8221; file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 10pt;\">\/*\n * sock_cgroup_data is embedded at sock-&gt;sk_cgrp_data and contains\n * per-socket cgroup information except for memcg association.\n *\n * On legacy hierarchies, net_prio and net_cls controllers directly set\n * attributes on each sock which can then be tested by the network layer.\n * On the default hierarchy, each sock is associated with the cgroup it was\n * created in and the networking layer can match the cgroup directly.\n *\n * To avoid carrying all three cgroup related fields separately in sock,\n * sock_cgroup_data overloads (prioidx, classid) and the cgroup pointer.\n * On boot, sock_cgroup_data records the cgroup that the sock was created\n * in so that cgroup2 matches can be made; however, once either net_prio or\n * net_cls starts being used, the area is overriden to carry prioidx and\/or\n * classid.  The two modes are distinguished by whether the lowest bit is\n * set.  Clear bit indicates cgroup pointer while set bit prioidx and\n * classid.\n *\n * While userland may start using net_prio or net_cls at any time, once\n * either is used, cgroup2 matching no longer works.  There is no reason to\n * mix the two and this is in line with how legacy and v2 compatibility is\n * handled.  On mode switch, cgroup references which are already being\n * pointed to by socks may be leaked.  While this can be remedied by adding\n * synchronization around sock_cgroup_data, given that the number of leaked\n * cgroups is bound and highly unlikely to be high, this seems to be the\n * better trade-off.\n *\/<\/span><\/code><\/pre>\n\n\n\n<p>and later:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/*\n * There's a theoretical window where the following accessors race with\n * updaters and return part of the previous pointer as the prioidx or\n * classid.  Such races are short-lived and the result isn't critical.\n *\/<\/code><\/pre>\n\n\n\n<p>This means that sock_cgroup_data &#8220;carries&#8221; the information whether net_prio or net_cls starts being used and in such case sock_cgroup_data overloads (prioidx, classid) and the cgroup pointer. In our crash we can extract this information:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>crash> print\/a ((struct sock *)0xffff9ce3de26b280)->sk_cgrp_data\n$5 = {\n  {\n    {\n      is_data = 0x0,\n      padding = 0x68,\n      prioidx = 0xe241,\n      classid = 0xffff9ce3\n    },\n    val = 0xffff9ce3e2416800\n  }\n}<\/code><\/pre>\n\n\n\n<p>Described socket keeps the &#8220;sk_cgrp_data&#8221; pointer with the information of being &#8220;attached&#8221; to the cgroup2. However, cgroup2 has been destroyed.<br>Now we have all the information to solve the mystery of this bug:<\/p>\n\n\n\n<ol>\n<li>Process creates a socket and both of them are inside some cgroup v2 (non-root)\n<ul>\n<li>cgroup BPF is cgroup2 only<\/li>\n<\/ul>\n<\/li>\n<li>At some point net_prio or net_cls is being used:\n<ul>\n<li>this operation is disabling cgroup2 socket matching<\/li>\n<li>now, all related sockets should be converted to use net_prio, and sk_cgrp_data should be updated<\/li>\n<\/ul>\n<\/li>\n<li>The socket is cloned, but not the reference to the cgroup (ref: point 1)\n<ul>\n<li>this essentially moves the socket to the new cgroup<\/li>\n<\/ul>\n<\/li>\n<li>All tasks in the old cgroup (ref: point 1) must die and when this happens, this cgroup dies as well<\/li>\n<li>When original process is starting to &#8220;use&#8221; the socket, it might attempt to access cgroup which is already &#8220;dead&#8221;. This essentially generates Use-After-Free condition\n<ul>\n<li>in my specific case, process was killed or invoked exit()<\/li>\n<li>during the execution of do_exit() function, all file descriptors and all sockets are being closed<\/li>\n<li>one of the socket still points to the previously destroyed cgroup2 BPF (OpenSSH might install BPF)<\/li>\n<li>__cgroup_bpf_run_filter_skb runs attached BPF and we have Use-After-Free<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>To confirm that scenario, I&#8217;ve modified some of the Linux kernel sources:<\/p>\n<ol>\n<li>Function cgroup_sk_alloc_disable():\n<ul>\n<li>I&#8217;ve added dump_stack();<\/li>\n<\/ul>\n<\/li>\n<li>Function cgroup_bpf_release():<br>\n<ul>\n<li>I&#8217;ve moved mutex to guard code responsible for walking through the cgroup hierarchy<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>I&#8217;ve managed to reproduce this bug again and this is what I can see in the logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">...\n[   72.061197] kmem.limit_in_bytes is deprecated and will be removed. Please report your usecase to linux-mm@kvack.org if you depend on this functionality.\n[   72.121572] cgroup: cgroup: disabling cgroup2 socket matching due to net_prio or net_cls activation\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n[   72.121574] CPU: 0 PID: 6958 Comm: kubelet Kdump: loaded Not tainted 5.7.0-g6 #32\n[   72.121574] Hardware name: VMware, Inc. VMware Virtual Platform\/440BX Desktop Reference Platform, BIOS 6.00 04\/13\/2018\n[   72.121575] Call Trace:\n[   72.121580]  dump_stack+0x50\/0x70\n[   72.121582]  cgroup_sk_alloc_disable.cold+0x11\/0x25\n                ^^^^^^^^^^^^^^^^^^^^^^^\n[   72.121584]  net_prio_attach+0x22\/0xa0\n                ^^^^^^^^^^^^^^^\n[   72.121586]  cgroup_migrate_execute+0x371\/0x430\n[   72.121587]  cgroup_attach_task+0x132\/0x1f0\n[   72.121588]  __cgroup1_procs_write.constprop.0+0xff\/0x140\n                ^^^^^^^^^^^^^^^^^^^^^^\n[   72.121590]  kernfs_fop_write+0xc9\/0x1a0\n[   72.121592]  vfs_write+0xb1\/0x1a0\n[   72.121593]  ksys_write+0x5a\/0xd0\n[   72.121595]  do_syscall_64+0x47\/0x190\n[   72.121596]  entry_SYSCALL_64_after_hwframe+0x44\/0xa9\n[   72.121598] RIP: 0033:0x48abdb\n[   72.121599] Code: ff e9 69 ff ff ff cc cc cc cc cc cc cc cc cc e8 7b 68 fb ff 48 8b 7c 24 10 48 8b 74 24 18 48 8b 54 24 20 48 8b 44 24 08 0f 05 &lt;48&gt; 3d 01 f0 ff ff 76 20 48 c7 44 24 28 ff ff ff ff 48 c7 44 24 30\n[   72.121600] RSP: 002b:000000c00110f778 EFLAGS: 00000212 ORIG_RAX: 0000000000000001\n[   72.121601] RAX: ffffffffffffffda RBX: 000000c000060000 RCX: 000000000048abdb\n[   72.121601] RDX: 0000000000000004 RSI: 000000c00110f930 RDI: 000000000000001e\n[   72.121601] RBP: 000000c00110f7c8 R08: 000000c00110f901 R09: 0000000000000004\n[   72.121602] R10: 000000c0011a39a0 R11: 0000000000000212 R12: 000000000000019b\n[   72.121602] R13: 000000000000019a R14: 0000000000000200 R15: 0000000000000000<\/span><\/code><\/pre>\n\n\n\n<p>As we can see, net_prio is being activated and cgroup2 socket matching is being disabled. Next:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">[  287.497527] percpu ref (cgroup_bpf_release_fn) &lt;= 0 (-79) after switching to atomic\n[  287.497535] WARNING: CPU: 0 PID: 9 at lib\/percpu-refcount.c:161 percpu_ref_switch_to_atomic_rcu+0x11f\/0x12a\n[  287.497536] Modules linked in:\n[  287.497537] CPU: 0 PID: 9 Comm: ksoftirqd\/0 Kdump: loaded Not tainted 5.7.0-g6 #32\n[  287.497538] Hardware name: VMware, Inc. VMware Virtual Platform\/440BX Desktop Reference Platform, BIOS 6.00 04\/13\/2018\n[  287.497539] RIP: 0010:percpu_ref_switch_to_atomic_rcu+0x11f\/0x12a<\/span><\/code><\/pre>\n\n\n\n<p>cgroup_bpf_release_fn is being executed multiple times. All cgroup BPF entries has been deleted and freed. Next:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span style=\"font-size: 8pt;\">[  287.543976] general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] PREEMPT SMP PTI\n[  287.544062] CPU: 0 PID: 11398 Comm: realpath Kdump: loaded Tainted: G        W         5.7.0-g6 #32\n[  287.544133] Hardware name: VMware, Inc. VMware Virtual Platform\/440BX Desktop Reference Platform, BIOS 6.00 04\/13\/2018\n[  287.544217] RIP: 0010:__cgroup_bpf_run_filter_skb+0xd4\/0x230\n[  287.544267] Code: 00 48 01 c8 48 89 43 50 41 83 ff 01 0f 84 c2 00 00 00 e8 6f 55 f1 ff e8 5a 3e f5 ff 44 89 fa 48 8d 84 d5 e0 03 00 00 48 8b 00 &lt;48&gt; 8b 78 10 4c 8d 78 10 48 85 ff 0f 84 29 01 00 00 bd 01 00 00 00\n[  287.544398] RSP: 0018:ffff957740003af8 EFLAGS: 00010206\n[  287.544446] RAX: 6b6b6b6b6b6b6b6b RBX: ffff8911f339cf00 RCX: 0000000000000028\n[  287.544506] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000001\n[  287.544566] RBP: ffff8911e2eb5000 R08: 0000000000000000 R09: 0000000000000001\n[  287.544625] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000014\n[  287.544685] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000000\n[  287.544753] FS:  00007f86e885a580(0000) GS:ffff8911f6e00000(0000) knlGS:0000000000000000\n[  287.544833] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033\n[  287.544919] CR2: 000055fb75e86da4 CR3: 0000000221316003 CR4: 00000000003606f0\n[  287.544996] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000\n[  287.545063] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400\n[  287.545129] Call Trace:\n[  287.545167]  &lt;IRQ&gt;\n[  287.545204]  sk_filter_trim_cap+0x10c\/0x250\n[  287.545253]  ? nf_ct_deliver_cached_events+0xb6\/0x120\n[  287.545308]  ? tcp_v4_inbound_md5_hash+0x47\/0x160\n[  287.545359]  tcp_v4_rcv+0xb49\/0xda0\n[  287.545404]  ? nf_hook_slow+0x3a\/0xa0\n[  287.545449]  ip_protocol_deliver_rcu+0x26\/0x1d0\n[  287.545500]  ip_local_deliver_finish+0x50\/0x60\n[  287.545550]  ip_sublist_rcv_finish+0x38\/0x50\n[  287.545599]  ip_sublist_rcv+0x16d\/0x200\n[  287.545645]  ? ip_rcv_finish_core.constprop.0+0x470\/0x470\n[  287.545701]  ip_list_rcv+0xf1\/0x115\n[  287.545746]  __netif_receive_skb_list_core+0x249\/0x270\n[  287.545801]  netif_receive_skb_list_internal+0x19f\/0x2c0\n[  287.545856]  napi_complete_done+0x8e\/0x130\n[  287.545905]  e1000_clean+0x27e\/0x600\n[  287.545951]  ? security_cred_free+0x37\/0x50\n[  287.545999]  net_rx_action+0x133\/0x3b0\n[  287.546045]  __do_softirq+0xfc\/0x331\n[  287.546091]  irq_exit+0x92\/0x110\n[  287.546133]  do_IRQ+0x6d\/0x120\n[  287.546175]  common_interrupt+0xf\/0xf\n[  287.546219]  &lt;\/IRQ&gt;\n[  287.546255] RIP: 0010:__x64_sys_exit_group+0x4\/0x10<\/span><\/code><\/pre>\n\n\n\n<p>We have our crash referencing freed memory.&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong><span class=\"underline\" style=\"text-decoration: underline;\">First CVE &#8211; CVE-2020-14356:<\/span><\/strong><\/p>\n\n\n\n<p>I&#8217;ve decided to report this issue to the Linux Kernel security mailing list around the mid-July (2020). Roman Gushchin replied to my report and suggested to verify if I can still repro this issue when commit ad0f75e5f57c (&#8220;cgroup: fix cgroup_sk_alloc() for sk_clone_lock()&#8221;) is applied. This commit was merged to the Linux Kernel git source tree just a few days before my report. I&#8217;ve carefully verified it and indeed it fixed the problem. However, commit ad0f75e5f57c is not fully complete and a follow-up fix 14b032b8f8fc (&#8220;cgroup: Fix sock_cgroup_data on big-endian.&#8221;) should be applied as well.<\/p>\n<p><br \/>After this conversation Greg KH decided to backport Roman&#8217;s patches to the LTS kernels. In the meantime, I&#8217;ve decided to apply for CVE number (through RedHat) to track this issue:<\/p>\n<ol>\n<li>CVE-2020-14356 was allocated to track this issue<\/li>\n<li>For some unknown reasons, this bug was classified as NULL pointer dereference \ud83d\ude42<\/li>\n<\/ol>\n<p>RedHat correctly acknowledged this issue as Use-After-Free and in their own description and bugzilla they specify:<\/p>\n<ul style=\"list-style-type: circle;\">\n<li>&#8220;A use-after-free flaw was found in the Linux kernel\u2019s cgroupv2 (&#8230;)&#8221;<br \/><a href=\"https:\/\/access.redhat.com\/security\/cve\/cve-2020-14356\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/access.redhat.com\/security\/cve\/cve-2020-14356<\/a><\/li>\n<li>&#8220;It was found that the Linux kernel&#8217;s use after free issue (&#8230;)&#8221;<br \/><a href=\"https:\/\/bugzilla.redhat.com\/show_bug.cgi?id=1868453\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/bugzilla.redhat.com\/show_bug.cgi?id=1868453<\/a><\/li>\n<\/ul>\n<p>However, in CVE MITRE portal we can see a very inaccurate description:<\/p>\n<ul style=\"list-style-type: circle;\">\n<li>&#8220;A flaw null pointer dereference in the Linux kernel cgroupv2 subsystem in versions before 5.7.10 was found in the way when reboot the system. A local user could use this flaw to crash the system or escalate their privileges on the system.&#8221;<br \/><a href=\"https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2020-14356\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2020-14356<\/a><\/li>\n<\/ul>\n<p>First, it is not NULL pointer dereference but Use-After-Free bug. Maybe it is badly classified based on that opened bug:<br \/><a href=\"https:\/\/bugzilla.kernel.org\/show_bug.cgi?id=208003\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/bugzilla.kernel.org\/show_bug.cgi?id=208003<\/a><\/p>\n<p>People have started to hit this Use-After-Free bug in the form of NULL pointer dereference &#8220;kernel panic&#8221;.<\/p>\n<p>Additionally, the entire description of the bug is wrong. I&#8217;ve raised that concern to the CVE MITRE but the invalid description is still there. There is also a small Twitter discussion about that here:<br \/><a href=\"https:\/\/twitter.com\/Adam_pi3\/status\/1296212546043740160\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/twitter.com\/Adam_pi3\/status\/1296212546043740160<\/a><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong><span class=\"underline\" style=\"text-decoration: underline;\">Second CVE &#8211; CVE-2020-25220:<\/span><\/strong><\/p>\n\n\n\n<p>During analysis of this bug, I contacted Brad Spengler. When the patch for this issue was backported to LTS kernels, Brad noticed that it conflicted with his pre-existing backport, and that the upstream backport looked incorrect. I was surprised since I had reviewed the original commit for mainline kernel (5.7) and it was fine. Having this in mind, I decided to carefully review the backported patch:<br><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/stable\/linux.git\/commit\/?h=linux-4.14.y&amp;id=82fd2138a5ffd7e0d4320cdb669e115ee976a26e\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/stable\/linux.git\/commit\/?h=linux-4.14.y&amp;id=82fd2138a5ffd7e0d4320cdb669e115ee976a26e<\/a><\/p>\n\n\n\n<p>and it really looks incorrect. Part of the original fix is the following code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+void cgroup_sk_clone(struct sock_cgroup_data *skcd)\n+{\n+   if (skcd->val) {\n+       if (skcd->no_refcnt)\n+           return;\n+       \/*\n+        * We might be cloning a socket which is left in an empty\n+        * cgroup and the cgroup might have already been rmdir'd.\n+        * Don't use cgroup_get_live().\n+        *\/\n+       cgroup_get(sock_cgroup_ptr(skcd));\n+       cgroup_bpf_get(sock_cgroup_ptr(skcd));\n+   }\n+}<\/code><\/pre>\n\n\n\n<p>However, backported patch has the following logic:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+void cgroup_sk_clone(struct sock_cgroup_data *skcd)\n+{\n+   \/* Socket clone path *\/\n+   if (skcd->val) {\n+       \/*\n+        * We might be cloning a socket which is left in an empty\n+        * cgroup and the cgroup might have already been rmdir'd.\n+        * Don't use cgroup_get_live().\n+        *\/\n+       cgroup_get(sock_cgroup_ptr(skcd));\n+   }\n+}<\/code><\/pre>\n\n\n\n<p>There is a missing check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+       if (skcd->no_refcnt)\n+           return;<\/code><\/pre>\n\n\n\n<p>which could result in reference counter bug and in the end Use-After-Free again. It looks like the backported patch for stable kernels is still buggy.<\/p>\n\n\n\n<p>I&#8217;ve contacted RedHat again and they started to provide correct patches for their own kernels. However, LTS kernels were still buggy. I&#8217;ve also asked to assign a separate CVE for that issue but RedHat suggested that I do it myself.<\/p>\n\n\n\n<p>After that, I went for vacation and forgot about this issue \ud83d\ude42 Recently, I&#8217;ve decided to apply for CVE to track the &#8220;bad patch&#8221; issue, and CVE-2020-25220 was allocated. It is worth to point out that someone from Huawei at some point realized that patch is wrong and LTS got a correct fix as well:<\/p>\n\n\n\n<p><a href=\"https:\/\/www.spinics.net\/lists\/stable\/msg405099.html\">https:\/\/www.spinics.net\/lists\/stable\/msg405099.html<\/a><\/p>\n\n\n\n<p>What is worth to mention, grsecurity backport was never affected by the CVE-2020-25220.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong><span class=\"underline\" style=\"text-decoration: underline;\">Summary<\/span><\/strong>:<\/p>\n\n\n\n<p>Original issue, tracked by CVE-2020-14356, affects kernels starting from 4.5+ up to 5.7.10.<\/p>\n<ul>\n<li>RedHat correctly fixed all their kernels, and has proper description of the bug<\/li>\n<li>CVE MITRE still has invalid and misleading description<\/li>\n<\/ul>\n<p>Badly backported patch, tracked by CVE-2020-25220, affects kernels:<\/p>\n<ul>\n<li>4.19 until version 4.19.140 (exclusive)<\/li>\n<li>4.14 until version 4.14.194 (exclusive)<\/li>\n<li>4.9 until version 4.9.233 (exclusive)<\/li>\n<\/ul>\n<p>*grsecurity kernels were never affected by the CVE-2020-25220<\/p>\n<p><br>Best regards,<br>Adam &#8216;pi3&#8217; Zabrocki<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The short story of 1 Linux Kernel Use-After-Free bug and 2 CVEs (CVE-2020-14356 and CVE-2020-25220) Name:&nbsp;&nbsp;&nbsp;&nbsp; Linux kernel Cgroup BPF Use-After-FreeAuthor:&nbsp;&nbsp; Adam Zabrocki (pi3@pi3.com.pl)Date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; May 27, 2020<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4,5],"tags":[],"class_list":["post-720","post","type-post","status-publish","format-standard","hentry","category-bughunt","category-exploiting"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/720","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=720"}],"version-history":[{"count":55,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/720\/revisions"}],"predecessor-version":[{"id":778,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/720\/revisions\/778"}],"wp:attachment":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}