aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2025-02-18 15:12:31 +0000
committerAleksandr Nogikh <nogikh@google.com>2025-02-21 17:21:17 +0000
commitd34966d146f584d390b49f213d1fccd59548dc6d (patch)
treed400f6becc0b35195e23fccc7d87077b3eaaa4f9
parent0808a665bc75ab0845906bfeca0d12fb520ae6eb (diff)
executor: fix cover_protect() on FreeBSD
During machine checks, syzkaller will execute calls with coverage disabled, in which case per-thread coverage structures are zeroed out. write_output() will temporarily map the coverage data as writeable via CoverAccessScope, whether or not cover is enabled. In effect, write_output() may trigger a call mprotect(0, kCoverSize, PROT_RW). On FreeBSD, mprotect() silently ignores unmapped regions, so this does not result in an error. In fact, kCoverSize is now large enough that this ends up removing the eXecute bit from part of syz-executor's text region. Make CoverAccessScope a no-op if coverage is not enabled. Modify BSD cover_protect() and cover_unprotect() to fail if invoked when coverage is disabled.
-rw-r--r--executor/executor.cc6
-rw-r--r--executor/executor_bsd.h4
2 files changed, 8 insertions, 2 deletions
diff --git a/executor/executor.cc b/executor/executor.cc
index 7a0c115b8..a262bff83 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -521,11 +521,13 @@ public:
if (used_)
fail("recursion in CoverAccessScope");
used_ = true;
- cover_unprotect(cov_);
+ if (flag_coverage)
+ cover_unprotect(cov_);
}
~CoverAccessScope()
{
- cover_protect(cov_);
+ if (flag_coverage)
+ cover_protect(cov_);
used_ = false;
}
diff --git a/executor/executor_bsd.h b/executor/executor_bsd.h
index 0eb76c588..b7cbdd4f5 100644
--- a/executor/executor_bsd.h
+++ b/executor/executor_bsd.h
@@ -120,6 +120,8 @@ static void cover_mmap(cover_t* cov)
static void cover_protect(cover_t* cov)
{
+ if (cov->data == NULL)
+ fail("cover_protect invoked on an unmapped cover_t object");
#if GOOS_freebsd
size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE;
long page_size = sysconf(_SC_PAGESIZE);
@@ -139,6 +141,8 @@ static void cover_protect(cover_t* cov)
static void cover_unprotect(cover_t* cov)
{
+ if (cov->data == NULL)
+ fail("cover_unprotect invoked on an unmapped cover_t object");
#if GOOS_freebsd
size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE;
mprotect(cov->data, mmap_alloc_size, PROT_READ | PROT_WRITE);