aboutsummaryrefslogtreecommitdiffstats
path: root/executor/executor_linux.h
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-08-14 17:46:34 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-08-16 09:31:43 +0000
commitc3a6603be2cc031a8f2fa69e757e04a4ce647080 (patch)
tree863f68e6614951e732460b4725dd114fcedcfb7b /executor/executor_linux.h
parent5340a9ab4c1ab7801ad1055041dec2c2ff50a254 (diff)
executor: protect kcov/output regions with pkeys
Protect KCOV regions with pkeys if they are available. Protect output region with pkeys in snapshot mode. Snapshot mode is especially sensitive to output buffer corruption since its location is not randomized.
Diffstat (limited to 'executor/executor_linux.h')
-rw-r--r--executor/executor_linux.h28
1 files changed, 28 insertions, 0 deletions
diff --git a/executor/executor_linux.h b/executor/executor_linux.h
index 072831816..82a1d559a 100644
--- a/executor/executor_linux.h
+++ b/executor/executor_linux.h
@@ -11,6 +11,8 @@
#include <sys/syscall.h>
#include <unistd.h>
+static bool pkeys_enabled;
+
const unsigned long KCOV_TRACE_PC = 0;
const unsigned long KCOV_TRACE_CMP = 1;
@@ -65,6 +67,22 @@ static void os_init(int argc, char** argv, char* data, size_t data_size)
struct sigaction act = {};
act.sa_handler = [](int) {};
sigaction(SIGCHLD, &act, nullptr);
+
+ // Use the last available pkey so that C reproducers get the the same keys from pkey_alloc.
+ int pkeys[RESERVED_PKEY + 1];
+ int npkey = 0;
+ for (; npkey <= RESERVED_PKEY; npkey++) {
+ int pk = pkey_alloc(0, 0);
+ if (pk == -1)
+ break;
+ if (pk == RESERVED_PKEY) {
+ pkeys_enabled = true;
+ break;
+ }
+ pkeys[npkey] = pk;
+ }
+ while (npkey--)
+ pkey_free(pkeys[npkey]);
}
static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs])
@@ -87,14 +105,20 @@ static void cover_open(cover_t* cov, bool extra)
if (ioctl(cov->fd, kcov_init_trace, cover_size))
fail("cover init trace write failed");
cov->mmap_alloc_size = cover_size * (is_kernel_64_bit ? 8 : 4);
+ if (pkeys_enabled)
+ debug("pkey protection enabled\n");
}
static void cover_protect(cover_t* cov)
{
+ if (pkeys_enabled && pkey_set(RESERVED_PKEY, PKEY_DISABLE_WRITE))
+ debug("pkey_set failed: %d\n", errno);
}
static void cover_unprotect(cover_t* cov)
{
+ if (pkeys_enabled && pkey_set(RESERVED_PKEY, 0))
+ debug("pkey_set failed: %d\n", errno);
}
static void cover_mmap(cover_t* cov)
@@ -113,6 +137,8 @@ static void cover_mmap(cover_t* cov)
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, cov->fd, 0);
if (cov->data == MAP_FAILED)
exitf("cover mmap failed");
+ if (pkeys_enabled && pkey_mprotect(cov->data, cov->mmap_alloc_size, PROT_READ | PROT_WRITE, RESERVED_PKEY))
+ exitf("failed to pkey_mprotect kcov buffer");
cov->data_end = cov->data + cov->mmap_alloc_size;
cov->data_offset = is_kernel_64_bit ? sizeof(uint64_t) : sizeof(uint32_t);
cov->pc_offset = 0;
@@ -151,7 +177,9 @@ static void cover_reset(cover_t* cov)
fail("cover_reset: current_thread == 0");
cov = &current_thread->cov;
}
+ cover_unprotect(cov);
*(uint64*)cov->data = 0;
+ cover_protect(cov);
}
static void cover_collect(cover_t* cov)