The problem is when the sock object gets cloned via dccp_create_openreq_child(),
it gives all its attributes to the child sock object, and no reference counter
is taken for the object dccps_hc_tx_ccid.
If one of the sock objects (the parent or the cahild) is closes or disconnected,
it frees the target objects dccps_hc_tx_ccid and provides us a dagling pointer in the other sock object.
This causes an exploitable double free for an object contains function pointers.
We can free dccps_hc_tx_ccid by calling connect(AF_UNSPEC),then spray the heap with other allocations,
then call close() we'll potentially have a RIP control.
This chunk of code is the responsible of freeing dccps_hc_tx_ccid, if called again it will call
ccid_hc_tx_exit() from a freed object
void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
{
if (ccid != NULL) {
if (ccid->ccid_ops->ccid_hc_tx_exit != NULL)
ccid->ccid_ops->ccid_hc_tx_exit(sk); // <-- Calling a function pointer
kmem_cache_free(ccid->ccid_ops->ccid_hc_tx_slab, ccid);
}
}
disassembly :
(gdb) disas ccid_hc_tx_delete
Dump of assembler code for function ccid_hc_tx_delete:
0xffffffff81a7a3a0 <+0>: test rdi,rdi
0xffffffff81a7a3a3 <+3>: je 0xffffffff81a7a3cd <ccid_hc_tx_delete+45>
0xffffffff81a7a3a5 <+5>: push rbx
0xffffffff81a7a3a6 <+6>: mov rbx,rdi
0xffffffff81a7a3a9 <+9>: mov rdi,rsi
0xffffffff81a7a3ac <+12>: mov rax,QWORD PTR [rbx]
0xffffffff81a7a3af <+15>: mov rdx,QWORD PTR [rax+0x80] <— rax points to a freed object
0xffffffff81a7a3b6 <+22>: test rdx,rdx
0xffffffff81a7a3b9 <+25>: je 0xffffffff81a7a3c0 <ccid_hc_tx_delete+32>
I found this exploitable bug in Linux Kernel which affects all ubuntu distributions, /git.kernel. org/pub/ scm/linux/ kernel/ git/stable/ linux.git/ commit/ ?h=linux- 3.2.y&id= e23d13a89d8ca5f e717d75248672e1 b8bc4a3be8.
I have responsibly disclosed and patched a pretty similar bug in late 2017, you can
see the work here : https:/
But the bug appears again in a different look and still affect the kernel.
The problem is when the sock object gets cloned via dccp_create_ openreq_ child() ,
it gives all its attributes to the child sock object, and no reference counter
is taken for the object dccps_hc_tx_ccid.
If one of the sock objects (the parent or the cahild) is closes or disconnected,
it frees the target objects dccps_hc_tx_ccid and provides us a dagling pointer in the other sock object.
This causes an exploitable double free for an object contains function pointers.
We can free dccps_hc_tx_ccid by calling connect( AF_UNSPEC) ,then spray the heap with other allocations,
then call close() we'll potentially have a RIP control.
This chunk of code is the responsible of freeing dccps_hc_tx_ccid, if called again it will call
ccid_hc_tx_exit() from a freed object
void ccid_hc_ tx_delete( struct ccid *ccid, struct sock *sk) ccid_ops- >ccid_hc_ tx_exit != NULL) >ccid_ops- >ccid_hc_ tx_exit( sk); // <-- Calling a function pointer cache_free( ccid->ccid_ ops->ccid_ hc_tx_slab, ccid);
{
if (ccid != NULL) {
if (ccid->
ccid-
kmem_
}
}
disassembly :
(gdb) disas ccid_hc_tx_delete a7a3a0 <+0>: test rdi,rdi a7a3a3 <+3>: je 0xffffffff81a7a3cd <ccid_hc_ tx_delete+ 45> a7a3a5 <+5>: push rbx a7a3a6 <+6>: mov rbx,rdi a7a3a9 <+9>: mov rdi,rsi a7a3ac <+12>: mov rax,QWORD PTR [rbx]
Dump of assembler code for function ccid_hc_tx_delete:
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81 a7a3af <+15>: mov rdx,QWORD PTR [rax+0x80] <— rax points to a freed object
0xffffffff81 a7a3b6 <+22>: test rdx,rdx a7a3b9 <+25>: je 0xffffffff81a7a3c0 <ccid_hc_ tx_delete+ 32>
0xffffffff81
0xffffffff81 a7a3bb <+27>: call rdx // <-- arbitrary call
0xffffffff81 a7a3bd <+29>: mov rax,QWORD PTR [rbx] a7a3c0 <+32>: mov rsi,rbx a7a3c3 <+35>: mov rdi,QWORD PTR [rax+0x18] a7a3c7 <+39>: pop rbx a7a3c8 <+40>: jmp 0xffffffff811fb980 <kmem_cache_free> a7a3cd <+45>: repz ret
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81
0xffffffff81
End of assembler dump.