Nytro Posted December 10, 2016 Report Posted December 10, 2016 CVE-2016-8655 Linux af_packet.c race condition (local root) From: Philip Pettersson <philip.pettersson () gmail com> Date: Tue, 6 Dec 2016 11:50:57 +0900 Hello, This is an announcement about CVE-2016-8655 which is a race-condition I found in Linux (net/packet/af_packet.c). It can be exploited to gain kernel code execution from unprivileged processes. The bug was introduced on Aug 19, 2011: https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a Fixed on Nov 30, 2016: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c =*=*=*=*=*=*=*=*= BUG DETAILS =*=*=*=*=*=*=*=*= To create AF_PACKET sockets you need CAP_NET_RAW in your network namespace, which can be acquired by unprivileged processes on systems where unprivileged namespaces are enabled (Ubuntu, Fedora, etc). It can be triggered from within containers to compromise the host kernel. On Android, processes with gid=3004/AID_NET_RAW are able to create AF_PACKET sockets (mediaserver) and can trigger the bug. I found the bug by reading code paths that have been opened up by the emergence of unprivileged namespaces, something I think should be off by default in all Linux distributions given its history of security vulnerabilities. The problem is inside packet_set_ring() and packet_setsockopt(). We can reach packet_set_ring() by calling setsockopt() on the socket using the PACKET_RX_RING option. If the version of the packet socket is TPACKET_V3, a timer_list object will be initialized by packet_set_ring() when it calls init_prb_bdqc(). ... switch (po->tp_version) { case TPACKET_V3: /* Transmit path is not supported. We checked * it above but just being paranoid */ if (!tx_ring) init_prb_bdqc(po, rb, pg_vec, req_u); break; default: break; } ... The function flow to set up the timer is: packet_set_ring()->init_prb_bdqc()->prb_setup_retire_blk_timer()-> prb_init_blk_timer()->prb_init_blk_timer()->init_timer() When the socket is closed, packet_set_ring() is called again to free the ring buffer and delete the previously initialized timer if the packet version is > TPACKET_V2: ... if (closing && (po->tp_version > TPACKET_V2)) { /* Because we don't support block-based V3 on tx-ring */ if (!tx_ring) prb_shutdown_retire_blk_timer(po, rb_queue); } ... The issue is that we can change the packet version to TPACKET_V1 with packet_setsockopt() after init_prb_bdqc() has been executed and before packet_set_ring() has returned. There is an attempt to deny changing socket versions after a ring buffer has been initialized, but it is insufficient: ... case PACKET_VERSION: { ... if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) return -EBUSY; ... There's plenty of room to race this code path between the calls to init_prb_bdqc() and swap(rb->pg_vec, pg_vec) in packet_set_ring(). When the socket is closed, packet_set_ring() will not delete the timer since the socket version is now TPACKET_V1. The struct timer_list that describes the timer object is located inside the struct packet_sock for the socket itself however and will be freed with a call to kfree(). We then have a use-after-free on a timer object that can be exploited by various poisoning attacks on the SLAB allocator (I find add_key() to be the most reliable). This will ultimately lead to the kernel jumping to a manipulated function pointer when the timer expires. The bug is fixed by taking lock_sock(sk) in packet_setsockopt() when changing the packet version while also taking the lock at the start of packet_set_ring(). My exploit defeats SMEP/SMAP and will give a rootshell on Ubuntu 16.04, I will hold off a day on publishing it so people have some time to update. New Ubuntu kernels are out so please update as soon as possible. =*=*=*=*=*=*=*=*= TIMELINE =*=*=*=*=*=*=*=*= 2016-11-28: Bug reported to security () kernel org 2016-11-30: Patch submitted to netdev, notification sent to linux-distros 2016-12-02: Patch committed to mainline kernel 2016-12-06: Public announcement =*=*=*=*=*=*=*=*= LINKS =*=*=*=*=*=*=*=*= https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-8655 https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c https://www.ubuntu.com/usn/usn-3151-1/ =*=*=*=*=*=*=*=*= CREDIT =*=*=*=*=*=*=*=*= Philip Pettersson Sursa: http://seclists.org/oss-sec/2016/q4/607 Quote
aelius Posted December 10, 2016 Report Posted December 10, 2016 Sursa este aici: https://packetstormsecurity.com/files/140063/Linux-Kernel-4.4.0-AF_PACKET-Race-Condition-Privilege-Escalation.html Vad ca doar pe kernel 4.x exista problema. Nu stiu de ce se grabesc pseudo distributiile astea sa puna ultimele versiuni asa repede, fara a fi testate. De exemplu, la Debian ai kernel 3.16.x pe stable. La Ubuntu ai kernel 4.x si deja a ajuns la ubuntu 16, desi este din 2004 spre diferenta de debian care e din 1994. Ma rog, eu vad asta ca pe o idiotenie. Faci un fix minor in ceva si schimbi versiunea deja. Ontopic: grsec facand restrictie pe /proc nu mai poti citi adresele acelea si rezolva 99% din problemele de genul. Linux ar trebui sa se inspire eventual din FreeBSD unde ai mai multa libertate si posibilitati mai multe de a face un sistem mai sigur. Eventual sa folosesca restrictiile default din posix si cap root/pivot_root din kernel. Linus Torvalds e prea mandru de el sa accepte faptul ca e un software engineer si nu un security guru. 2 Quote
Nytro Posted December 10, 2016 Author Report Posted December 10, 2016 Linus a spus de mai multe ori ca pe el il intereseaza mai mult ca Linux sa fie stabil, nu sigur. Cu alte cuvinte, e de preferat sa nu iei PANIC in locul a mai putine LOCAL privilege escalation. 1 Quote