executor: surround the data mapping with PROT_NONE pages

Surround the main data mapping with PROT_NONE pages to make virtual address layout more consistent
across different configurations (static/non-static build) and C repros.
One observed case before: executor had a mapping above the data mapping (output region),
while C repros did not have that mapping above, as the result in one case VMA had next link,
while in the other it didn't and it caused a bug to not reproduce with the C repro.

The bug that reproduces only with the mapping above:
https://lkml.org/lkml/2020/4/17/819
This commit is contained in:
Dmitry Vyukov 2020-04-18 14:43:29 +02:00
parent 6fe0f49646
commit 365fba2440
8 changed files with 36 additions and 16 deletions

View File

@ -356,7 +356,7 @@ int main(int argc, char** argv)
start_time_ms = current_time_ms();
os_init(argc, argv, (void*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE);
os_init(argc, argv, (char*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE);
#if SYZ_EXECUTOR_USES_SHMEM
if (mmap(&input_data[0], kMaxInput, PROT_READ, MAP_PRIVATE | MAP_FIXED, kInFd, 0) != &input_data[0])

View File

@ -59,12 +59,21 @@ static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst)
static bool detect_kernel_bitness();
static void os_init(int argc, char** argv, void* data, size_t data_size)
static void os_init(int argc, char** argv, char* data, size_t data_size)
{
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
is_kernel_64_bit = detect_kernel_bitness();
// Surround the main data mapping with PROT_NONE pages to make virtual address layout more consistent
// across different configurations (static/non-static build) and C repros.
// One observed case before: executor had a mapping above the data mapping (output region),
// while C repros did not have that mapping above, as the result in one case VMA had next link,
// while in the other it didn't and it caused a bug to not reproduce with the C repro.
if (mmap(data - SYZ_PAGE_SIZE, SYZ_PAGE_SIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != data - SYZ_PAGE_SIZE)
fail("mmap of left data PROT_NONE page failed");
if (mmap(data, data_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != data)
fail("mmap of data segment failed");
if (mmap(data + data_size, SYZ_PAGE_SIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != data + data_size)
fail("mmap of right data PROT_NONE page failed");
}
static __thread cover_t* current_cover;

View File

@ -16,7 +16,7 @@ func InitTarget(target *prog.Target) {
arch := &arch{
MAP_FIXED: target.GetConst("MAP_FIXED"),
}
target.MakeDataMmap = targets.MakePosixMmap(target, true)
target.MakeDataMmap = targets.MakePosixMmap(target, true, false)
target.Neutralize = arch.Neutralize
}

View File

@ -13,7 +13,7 @@ func InitTarget(target *prog.Target) {
unix: targets.MakeUnixNeutralizer(target),
}
target.MakeDataMmap = targets.MakePosixMmap(target, true)
target.MakeDataMmap = targets.MakePosixMmap(target, true, false)
target.Neutralize = arch.unix.Neutralize
}

View File

@ -48,7 +48,7 @@ func InitTarget(target *prog.Target) {
ARCH_SET_GS: target.ConstMap["ARCH_SET_GS"],
}
target.MakeDataMmap = targets.MakePosixMmap(target, true)
target.MakeDataMmap = targets.MakePosixMmap(target, true, true)
target.Neutralize = arch.neutralize
target.SpecialTypes = map[string]func(g *prog.Gen, typ prog.Type, old prog.Arg) (
prog.Arg, []*prog.Call){

View File

@ -13,7 +13,7 @@ func InitTarget(target *prog.Target) {
unix: targets.MakeUnixNeutralizer(target),
}
target.MakeDataMmap = targets.MakePosixMmap(target, false)
target.MakeDataMmap = targets.MakePosixMmap(target, false, false)
target.Neutralize = arch.unix.Neutralize
}

View File

@ -19,7 +19,7 @@ func InitTarget(target *prog.Target) {
S_IFCHR: target.GetConst("S_IFCHR"),
}
target.MakeDataMmap = targets.MakePosixMmap(target, false)
target.MakeDataMmap = targets.MakePosixMmap(target, false, false)
target.Neutralize = arch.neutralize
target.AnnotateCall = arch.annotateCall
}

View File

@ -8,18 +8,21 @@ import (
)
// MakePosixMmap creates a "normal" posix mmap call that maps the target data range.
func MakePosixMmap(target *prog.Target, exec bool) func() []*prog.Call {
// If exec is set, the mapping is mapped as PROT_EXEC.
// If contain is set, the mapping is surrounded by PROT_NONE pages.
// These flags should be in sync with what executor.
func MakePosixMmap(target *prog.Target, exec, contain bool) func() []*prog.Call {
meta := target.SyscallMap["mmap"]
prot := target.GetConst("PROT_READ") | target.GetConst("PROT_WRITE")
protRW := target.GetConst("PROT_READ") | target.GetConst("PROT_WRITE")
if exec {
prot |= target.GetConst("PROT_EXEC")
protRW |= target.GetConst("PROT_EXEC")
}
flags := target.GetConst("MAP_ANONYMOUS") | target.GetConst("MAP_PRIVATE") | target.GetConst("MAP_FIXED")
const invalidFD = ^uint64(0)
size := target.NumPages * target.PageSize
return func() []*prog.Call {
const invalidFD = ^uint64(0)
makeMmap := func(addr, size, prot uint64) *prog.Call {
args := []prog.Arg{
prog.MakeVmaPointerArg(meta.Args[0], 0, size),
prog.MakeVmaPointerArg(meta.Args[0], addr, size),
prog.MakeConstArg(meta.Args[1], size),
prog.MakeConstArg(meta.Args[2], prot),
prog.MakeConstArg(meta.Args[3], flags),
@ -32,13 +35,21 @@ func MakePosixMmap(target *prog.Target, exec bool) func() []*prog.Call {
i++
}
args = append(args, prog.MakeConstArg(meta.Args[i], 0))
mmapCall := &prog.Call{
return &prog.Call{
Meta: meta,
Args: args,
Ret: prog.MakeReturnArg(meta.Ret),
}
return []*prog.Call{mmapCall}
}
return func() []*prog.Call {
if contain {
return []*prog.Call{
makeMmap(^uint64(target.PageSize)+1, target.PageSize, 0),
makeMmap(0, size, protRW),
makeMmap(size, target.PageSize, 0),
}
}
return []*prog.Call{makeMmap(0, size, protRW)}
}
}