From cbca8e0f043495ea2332604d8ce066891710e861 Mon Sep 17 00:00:00 2001 From: Necip Fazil Yildiran Date: Wed, 29 Jul 2020 07:36:25 +0000 Subject: executor: added syz_io_uring_setup to wrap both setup and mmap It is hard for the fuzzer to generate correct programs using mmap calls with fuzzer-provided mmap length. This wrapper ensures correct length computation. --- executor/common_linux.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) (limited to 'executor') diff --git a/executor/common_linux.h b/executor/common_linux.h index 546e60b79..a7dfa2374 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -1355,7 +1355,7 @@ static long syz_emit_ethernet(volatile long a0, volatile long a1, volatile long } #endif -#if SYZ_EXECUTOR || __NR_syz_io_uring_submit || __NR_syz_io_uring_complete +#if SYZ_EXECUTOR || __NR_syz_io_uring_submit || __NR_syz_io_uring_complete || __NR_syz_io_uring_setup #define SIZEOF_IO_URING_SQE 64 #define SIZEOF_IO_URING_CQE 16 @@ -1435,6 +1435,90 @@ static long syz_io_uring_complete(volatile long a0) #endif +#if SYZ_EXECUTOR || __NR_syz_io_uring_setup + +struct io_sqring_offsets { + uint32 head; + uint32 tail; + uint32 ring_mask; + uint32 ring_entries; + uint32 flags; + uint32 dropped; + uint32 array; + uint32 resv1; + uint64 resv2; +}; + +struct io_cqring_offsets { + uint32 head; + uint32 tail; + uint32 ring_mask; + uint32 ring_entries; + uint32 overflow; + uint32 cqes; + uint64 resv[2]; +}; + +struct io_uring_params { + uint32 sq_entries; + uint32 cq_entries; + uint32 flags; + uint32 sq_thread_cpu; + uint32 sq_thread_idle; + uint32 features; + uint32 resv[4]; + struct io_sqring_offsets sq_off; + struct io_cqring_offsets cq_off; +}; + +#define IORING_OFF_SQ_RING 0 +#define IORING_OFF_SQES 0x10000000ULL + +#include +#include + +#ifndef __NR_io_uring_setup +#ifdef __alpha__ +#define __NR_io_uring_setup 535 +#else // !__alpha__ +#define __NR_io_uring_setup 425 +#endif +#endif // __NR_io_uring_setup + +// Wrapper for io_uring_setup and the subsequent mmap calls that map the ring and the sqes +static long syz_io_uring_setup(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5) +{ + // syzlang: syz_io_uring_setup(entries int32[1:IORING_MAX_ENTRIES], params ptr[inout, io_uring_params], addr_ring vma, addr_sqes vma, ring_ptr ptr[out, ring_ptr], sqes_ptr ptr[out, sqes_ptr]) fd_io_uring + // C: syz_io_uring_setup(uint32 entries, struct io_uring_params* params, void* mmap_addr_ring, void* mmap_addr_sqes, void** ring_ptr_out, void** sqes_ptr_out) // returns uint32 fd_io_uring + + // Cast to original + uint32 entries = (uint32)a0; + struct io_uring_params* setup_params = (struct io_uring_params*)a1; + void* vma1 = (void*)a2; + void* vma2 = (void*)a3; + void** ring_ptr_out = (void**)a4; + void** sqes_ptr_out = (void**)a5; + + uint32 fd_io_uring = syscall(__NR_io_uring_setup, entries, setup_params); + + // Compute the ring sizes + uint32 sq_ring_sz = setup_params->sq_off.array + setup_params->sq_entries * sizeof(uint32); + uint32 cq_ring_sz = setup_params->cq_off.cqes + setup_params->cq_entries * SIZEOF_IO_URING_CQE; + + // Asssumed IORING_FEAT_SINGLE_MMAP, which is always the case with the current implementation + // The implication is that the sq_ring_ptr and the cq_ring_ptr are the same but the + // difference is in the offsets to access the fields of these rings. + uint32 ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz; + *ring_ptr_out = mmap(vma1, ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQ_RING); + + uint32 sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE; + *sqes_ptr_out = mmap(vma2, sqes_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQES); + + return fd_io_uring; +} + +#endif + #if SYZ_EXECUTOR || __NR_syz_io_uring_submit static long syz_io_uring_submit(volatile long a0, volatile long a1, volatile long a2, volatile long a3) -- cgit mrf-deployment