From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 117925 invoked by alias); 6 Sep 2017 12:47:14 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Received: (qmail 117349 invoked by uid 89); 6 Sep 2017 12:47:14 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.2 required=5.0 tests=BAYES_50,GIT_PATCH_2,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.2 spammy=H*F:D*pt, messaging, Messaging, H*c:DelSp X-HELO: smtp.alunos.dcc.fc.up.pt Message-ID: <20170906144653.14363oywmmoc9ug4@webmail.alunos.dcc.fc.up.pt> Date: Wed, 06 Sep 2017 12:47:00 -0000 From: up201407890@alunos.dcc.fc.up.pt To: libc-alpha@sourceware.org Subject: use-after-free / double-free exploit mitigation MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; DelSp="Yes"; format="flowed" Content-Disposition: inline Content-Transfer-Encoding: quoted-printable User-Agent: Internet Messaging Program (IMP) H3 (4.2) X-SW-Source: 2017-09/txt/msg00238.txt.bz2 Hello list, What are your thoughts on adding a SAFE_FREE() macro to glibc: #define SAFE_FREE(x) do { if((x) !=3D 0x0) { free(x); (x) =3D (void *)0x1;= =20=20 } } while(0) After free(x), we set x to an address that will crash when=20=20 dereferenced (use-after-free), and will also crash when it's an=20=20 argument to free(). Note that NULL isn't used, because free(NULL) does=20=20 nothing, which might hide potential double-free bugs. The pointer passed to free() isn't always an lvalue we can assign to,=20=20 e.g free(func()), but when a var is used it will detect use-after-free=20=20 and double-free bugs by having the program crash instead of allowing=20=20 various heap grooms and further exploitation. Here's a trivial example, Crashes when use-after-free: $ cat test.c #include #include #define SAFE_FREE(x) do { if((x) !=3D 0x0) { free(x); (x)=3D(void *)0x1; }= =20=20 } while(0) struct unicorn_counter { int num; }; int main() { struct unicorn_counter* p_unicorn_counter; int* run_calc =3D malloc(sizeof(int)); *run_calc =3D 0; SAFE_FREE(run_calc); //SAFE_FREE(run_calc); p_unicorn_counter =3D malloc(sizeof(struct unicorn_counter)); p_unicorn_counter->num =3D 42; if (*run_calc) // use-after-free execlp("/usr/bin/id", "id", 0); } $ gcc test.c $ ./a.out Segmentation fault $ gdb ./a.out gdb$ r ... 0x4005ed : mov eax,DWORD PTR [rax] Stopped reason: SIGSEGV 0x00000000004005ed in main () gdb$ print /x $rax $1 =3D 0x1 Crashes when double-free, by uncommenting 2nd SAFE_FREE(run_calc): $ cat test.c #include #include #define SAFE_FREE(x) do { if((x) !=3D 0x0) { free(x); (x)=3D(void *)0x1; }= =20=20 } while(0) struct unicorn_counter { int num; }; int main() { struct unicorn_counter* p_unicorn_counter; int* run_calc =3D malloc(sizeof(int)); *run_calc =3D 0; SAFE_FREE(run_calc); SAFE_FREE(run_calc); // double-free p_unicorn_counter =3D malloc(sizeof(struct unicorn_counter)); p_unicorn_counter->num =3D 42; if (*run_calc) execlp("/usr/bin/id", "id", 0); } $ gcc test.c $ gdb ./a.out gdb$ r ... 0x7ffff7aad614 <__GI___libc_free+20>: mov rax,QWORD PTR [rdi-0x8] Stopped reason: SIGSEGV __GI___libc_free (mem=3D0x1) at malloc.c:2929 warning: Source file is more recent than executable. $ print /x $rdi $1 =3D 0x1 ---------------------------------------------------------------- This message was sent using IMP, the Internet Messaging Program.