blob: 0c332052a2299e1ac586eb4c3d87bc2ca78b0cbe [file] [log] [blame]
#include "cheri.hh"
#include "compartment-macros.h"
#include <cheriot-atomic.hh>
#include <compartment.h>
#include <errno.h>
#include <futex.h>
#include <stdlib.h>
#include <switcher.h>
int heap_claim_ephemeral(Timeout *timeout, const void *ptr, const void *ptr2)
{
void **hazards = switcher_thread_hazard_slots();
auto *epochCounter{const_cast<
cheriot::atomic<uint32_t> *>(SHARED_OBJECT_WITH_PERMISSIONS(
cheriot::atomic<uint32_t>, allocator_epoch, true, false, false, false))};
uint32_t epoch = epochCounter->load();
int values = 2;
// Skip processing pointers that don't refer to heap memory.
if (!heap_address_is_valid(ptr))
{
ptr = nullptr;
values--;
}
if (!heap_address_is_valid(ptr2))
{
ptr2 = nullptr;
values--;
}
// If neither pointer refers to heap memory, set without synchronizing. It
// doesn't matter if the revoker sees these or not, they cannot extend the
// lifetime of a heap object.
if (values == 0)
{
hazards[0] = nullptr;
hazards[1] = nullptr;
return 0;
}
uint32_t oldEpoch;
do
{
while (epoch & 1)
{
if (timeout->may_block())
{
Timeout t{1};
(void)futex_timed_wait(
&t,
reinterpret_cast<uint32_t *>(epochCounter),
epoch,
FutexPriorityInheritance);
timeout->elapse(t.elapsed);
}
else
{
return -ETIMEDOUT;
}
epoch = epochCounter->load();
}
hazards[0] = const_cast<void *>(ptr);
hazards[1] = const_cast<void *>(ptr2);
oldEpoch = epoch;
epoch = epochCounter->load();
} while (epoch != oldEpoch);
auto isValidOrNull = [](CHERI::Capability<const void> pointer) {
return pointer.is_valid() || (pointer == nullptr);
};
if (isValidOrNull(ptr) && isValidOrNull(ptr2))
{
return 0;
}
hazards[0] = nullptr;
hazards[1] = nullptr;
return -EINVAL;
}