Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ option (undefined_san "Enable undefined-behavior sanitizer" OFF)
option (thin_lto "Enable the Thin LTO plugin" OFF)
option (full_lto "Enable full LTO (compatibility)" OFF)

# create random hex string as stack protector canary
string(RANDOM LENGTH 16 ALPHABET 0123456789ABCDEF STACK_PROTECTOR_VALUE)

set(CAPABS "${CAPABS} -g -fstack-protector-strong -D_STACK_GUARD_VALUE_=0x${STACK_PROTECTOR_VALUE}")
set(CAPABS "${CAPABS} -g -fstack-protector-strong")

# Various global defines
# * NO_DEBUG disables output from the debug macro
Expand Down
1 change: 1 addition & 0 deletions api/kernel/cpuid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ namespace CPUID
AVX, // AVX Instructions
F16C, // 16-bit Floating Point Instructions
RDRAND, // RDRAND Instruction
RDSEED, // RDSEED Instruction

FPU, // Floating-Point Unit On-Chip
VME, // Virtual 8086 Mode Extensions
Expand Down
14 changes: 11 additions & 3 deletions api/kernel/rng.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@

#include <cstdlib>
#include <cstdint>
#include <delegate>

// Incorporate seed data into the system RNG state
extern void rng_absorb(const void* input, size_t bytes);

// Extract output from the system RNG
extern void rng_extract(void* output, size_t bytes);

// Try to reseed the RNG state somehow
extern void rng_reseed();
// Try to reseed the RNG state
extern void rng_reseed_init(delegate<void(uint64_t*)>, int rounds);

// Extract 32 bit integer from system RNG
inline uint32_t rng_extract_uint32()
Expand All @@ -40,6 +41,13 @@ inline uint32_t rng_extract_uint32()
return x;
}

// Extract 64 bit integer from system RNG
inline uint64_t rng_extract_uint64()
{
uint64_t x;
rng_extract(&x, sizeof(x));
return x;
}

#include <fs/fd_compatible.hpp>
class RNG : public FD_compatible {
Expand All @@ -50,7 +58,7 @@ class RNG : public FD_compatible {
return rng;
}

void init();
static void init();

private:
RNG() {}
Expand Down
9 changes: 8 additions & 1 deletion cmake/post.service.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,14 @@ if ("${PLATFORM}" STREQUAL "x86_solo5")
set(PRE_BSS_SIZE "--defsym PRE_BSS_AREA=0x200000")
endif()

set(LDFLAGS "-nostdlib -melf_${ELF} --eh-frame-hdr ${LD_STRIP} --script=${INSTALL_LOC}/${ARCH}/linker.ld ${PRE_BSS_SIZE}")
option(for_production "Stop the OS when conditions not suitable for production" ON)
if (for_production)
set(PROD_USE 0x2000)
else()
set(PROD_USE 0x1000)
endif()

set(LDFLAGS "-nostdlib -melf_${ELF} --eh-frame-hdr ${LD_STRIP} --script=${INSTALL_LOC}/${ARCH}/linker.ld ${PRE_BSS_SIZE} --defsym __for_production_use=${PROD_USE}")

set_target_properties(service PROPERTIES LINK_FLAGS "${LDFLAGS}")

Expand Down
7 changes: 7 additions & 0 deletions linux/src/os.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <kernel/os.hpp>
#include <kernel/events.hpp>
#include <kernel/rng.hpp>
#include <kernel/service.hpp>
#include <kernel/timers.hpp>
#include <system_log>
#include <sys/time.h>
#include <sys/random.h>
#include <malloc.h> // mallinfo()
#include <sched.h>
extern bool __libc_initialized;
Expand Down Expand Up @@ -101,6 +103,11 @@ void OS::start(const char* cmdline)
// setup timer system
Timers::init(begin_timer, stop_timers);
Timers::ready();
// seed RNG with entropy
char entropy[2048];
ssize_t rngres = getrandom(entropy, sizeof(entropy), 0);
assert(rngres == sizeof(entropy));
rng_absorb(entropy, sizeof(entropy));
// fake CPU frequency
using namespace std::chrono;
OS::cpu_khz_ = decltype(OS::cpu_freq()) {3000000ul};
Expand Down
2 changes: 1 addition & 1 deletion seed/service/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ set(SOURCES
set(DRIVERS
# virtionet # Virtio networking driver
# virtioblk # Virtio block device driver
#boot_logger # Enable lots of logging from boot stage
boot_logger # Enable lots of logging from boot stage

# Use "boot --drivers ." to see other drivers
)
Expand Down
3 changes: 3 additions & 0 deletions seed/service/service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <service>
#include <cstdio>
#include <isotime>
#include <kernel/cpuid.hpp>

void Service::start(const std::string& args)
{
Expand All @@ -27,4 +28,6 @@ void Service::start(const std::string& args)
printf("Hello world! Time is now %s\n", isotime::now().c_str());
printf("Args = %s\n", args.c_str());
printf("Try giving the service less memory, eg. 5MB in vm.json\n");
printf("CPU has RDRAND: %d\n", CPUID::has_feature(CPUID::Feature::RDRAND));
printf("CPU has RDSEED: %d\n", CPUID::has_feature(CPUID::Feature::RDSEED));
}
24 changes: 24 additions & 0 deletions src/arch/x86_64/apic_asm.asm
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,27 @@ reset_idtr:
__amd64_load_tr:
ltr di
ret

GLOBAL intel_rdrand:function
intel_rdrand:
mov eax, 0x1
retry_rdrand:
rdrand rcx
mov QWORD [rdi], rcx
cmovb ecx, eax
jae retry_rdrand
cmp ecx, 0x1
sete al
ret

GLOBAL intel_rdseed:function
intel_rdseed:
mov eax, 0x1
retry_rdseed:
rdseed rcx
mov QWORD [rdi], rcx
cmovb ecx, eax
jae retry_rdseed
cmp ecx, 0x1
sete al
ret
3 changes: 3 additions & 0 deletions src/kernel/cpuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace CPUID {
{Feature::SSE3,"SSE3"},
{Feature::SSSE3,"SSSE3"},
{Feature::RDRAND,"RDRAND"},
{Feature::RDSEED,"RDSEED"},
{Feature::XSAVE,"XSAVE"},
{Feature::FXSR,"FXSR"},
{Feature::AES,"AES"},
Expand Down Expand Up @@ -207,10 +208,12 @@ namespace

case Feature::SVM: return FeatureInfo { 0x80000001, 0, Register::ECX, 1u << 2 }; // Secure Virtual Machine (AMD-V)
case Feature::SSE4A: return FeatureInfo { 0x80000001, 0, Register::ECX, 1u << 6 }; // SSE4a
// Standard function 7
case Feature::AVX2: return FeatureInfo { 7, 0, Register::ECX, 1u << 5 }; // AVX2
case Feature::BMI1: return FeatureInfo { 7, 0, Register::ECX, 1u << 3 }; // BMI1
case Feature::BMI2: return FeatureInfo { 7, 0, Register::ECX, 1u << 8 }; // BMI2
case Feature::LZCNT: return FeatureInfo { 7, 0, Register::ECX, 1u << 5 }; // LZCNT
case Feature::RDSEED: return FeatureInfo { 7, 0, Register::EBX, 1u << 18 }; // RDSEED
default: throw std::out_of_range("Unimplemented CPU feature encountered");
}
}
Expand Down
27 changes: 23 additions & 4 deletions src/kernel/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#endif

#include <kernel/os.hpp>
#include <kernel/cpuid.hpp>
#include <kernel/rng.hpp>
#include <service>
#include <cstdio>
Expand All @@ -49,6 +50,10 @@ extern char _LOAD_START_;
extern char _ELF_END_;

bool __libc_initialized = false;
extern char __for_production_use;
inline static bool is_for_production_use() {
return &__for_production_use == (char*) 0x2000;
}

bool OS::power_ = true;
bool OS::boot_sequence_passed_ = false;
Expand Down Expand Up @@ -134,10 +139,6 @@ void OS::post_start()
// Dependent on the liveupdate location being set
SystemLog::initialize();

MYINFO("Initializing RNG");
PROFILE("RNG init");
RNG::get().init();

// Seed rand with 32 bits from RNG
srand(rng_extract_uint32());

Expand Down Expand Up @@ -169,6 +170,24 @@ void OS::post_start()
printf(" +--> Running [ %s ]\n", Service::name());
FILLINE('~');

// if we have disabled important checks, its unsafe for production
#if defined(LIBFUZZER_ENABLED) || defined(ARP_PASSTHROUGH) || defined(DISABLE_INET_CHECKSUMS)
const bool unsafe = true;
#else
// if we dont have a good random source, its unsafe for production
const bool unsafe = !CPUID::has_feature(CPUID::Feature::RDSEED)
&& !CPUID::has_feature(CPUID::Feature::RDRAND);
#endif
if (unsafe) {
printf(" +--> WARNiNG: Environment unsafe for production\n");
if (is_for_production_use()) {
printf(" +--> Stop option enabled. Shutting down now...\n");
OS::shutdown();
return;
}
FILLINE('~');
}

Service::start();
}

Expand Down
51 changes: 28 additions & 23 deletions src/kernel/rng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@
#include <algorithm>
#include <cstring>
#include <smp>
#define SHAKE_128_RATE (1600-256)/8

struct alignas(SMP_ALIGN) rng_state
{
uint64_t state[25];
int64_t reseed_counter = 0;
int32_t reseed_rounds = 0;
delegate<void(uint64_t*)> reseed_callback = nullptr;
};
static SMP::Array<rng_state> rng;
// every RESEED_RATE bytes entropy is refilled
static const int RESEED_RATE = 4096;

static inline uint64_t rotate_left(uint64_t input, size_t rot) {
return (input << rot) | (input >> (64-rot));
Expand Down Expand Up @@ -114,8 +120,6 @@ static void keccak_1600_p(uint64_t A[25]) {
}
}

#define SHAKE_128_RATE (1600-256)/8

static inline void xor_bytes(const uint8_t* in, uint8_t* out, size_t bytes)
{
for(size_t i = 0; i != bytes; ++i)
Expand All @@ -137,8 +141,18 @@ void rng_absorb(const void* input, size_t bytes)
keccak_1600_p(PER_CPU(rng).state);
absorbed += absorbing;
}
PER_CPU(rng).reseed_counter += RESEED_RATE * bytes;
}

static void reseed_now()
{
uint64_t value;
for (int i = 0; i < PER_CPU(rng).reseed_rounds; i++) {
PER_CPU(rng).reseed_callback(&value);
rng_absorb(&value, sizeof(value));
}
}

void rng_extract(void* output, size_t bytes)
{
size_t copied = 0;
Expand All @@ -150,28 +164,19 @@ void rng_extract(void* output, size_t bytes)
keccak_1600_p(PER_CPU(rng).state);
copied += copying;
}
// don't reseed if no callback to do so
if (PER_CPU(rng).reseed_callback == nullptr) return;
PER_CPU(rng).reseed_counter -= bytes;
// reseed when below certain entropy
if (PER_CPU(rng).reseed_counter < 0) {
PER_CPU(rng).reseed_counter = 0;
reseed_now();
}
}

void RNG::init()
void rng_reseed_init(delegate<void(uint64_t*)> func, int rounds)
{
// initialize random seed based on cycles since start
if (CPUID::has_feature(CPUID::Feature::RDRAND)) {
uint32_t rdrand_output[32];

for (size_t i = 0; i != 32; ++i) {
while (!rdrand32(&rdrand_output[i])) {}
}

rng_absorb(rdrand_output, sizeof(rdrand_output));
}
else {
// this is horrible, better solution needed here
for (size_t i = 0; i != 32; ++i) {
uint64_t clock = OS::cycles_since_boot();
// maybe additionally call something which will take
// variable time depending in some way on the processor
// state (clflush?) or a HAVEGE-like approach.
rng_absorb(&clock, sizeof(clock));
}
}
PER_CPU(rng).reseed_callback = func;
PER_CPU(rng).reseed_rounds = rounds;
reseed_now();
}
1 change: 1 addition & 0 deletions src/platform/x86_pc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ set(X86_PC_OBJECTS
cpu_freq_sampling.cpp
serial1.cpp
pic.cpp
rand.cpp
softreset.cpp
sanity_checks.cpp
smbios.cpp
Expand Down
45 changes: 28 additions & 17 deletions src/platform/x86_pc/kernel_start.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
// limitations under the License.

#include <kernel/os.hpp>
#include <kernel/syscalls.hpp>
#include <kernel/cpuid.hpp>
#include <kernel/rng.hpp>
#include <kernel/syscalls.hpp>
#include <boot/multiboot.h>
#include <kprint>
#include <debug>
Expand Down Expand Up @@ -185,8 +186,24 @@ void kernel_start(uint32_t magic, uint32_t addr)
}
#endif

// initialize RNG as early as possible
RNG::init();

// Build AUX-vector for C-runtime
auxv_t aux[38];
std::array<char*, 6 + 38*2> argv;
// Parameters to main
argv[0] = (char*) Service::name();
argv[1] = 0x0;
int argc = 1;

// Env vars
argv[2] = strdup("LC_CTYPE=C");
argv[3] = strdup("LC_ALL=C");
argv[4] = strdup("USER=root");
argv[5] = 0x0;

// auxiliary vector
auxv_t* aux = (auxv_t*) &argv[6];
PRATTLE("* Initializing aux-vector @ %p\n", aux);

int i = 0;
Expand All @@ -211,22 +228,16 @@ void kernel_start(uint32_t magic, uint32_t addr)

const char* plat = "x86_64";
aux[i++].set_ptr(AT_PLATFORM, plat);
aux[i++].set_long(AT_NULL, 0);

std::array<char*, 6 + 38> argv;

// Parameters to main
argv[0] = (char*) Service::name();
argv[1] = 0x0;
int argc = 1;

// Env vars
argv[2] = strdup("LC_CTYPE=C");
argv[3] = strdup("LC_ALL=C");
argv[4] = strdup("USER=root");
argv[5] = 0x0;

memcpy(&argv[6], aux, sizeof(auxv_t) * 38);
// SSP value generated from system RNG
// The second byte will be zero, to catch string copying algorithms
const long canary = rng_extract_uint64() & 0xFFFFFFFFFFFF00FFul;
const long canary_idx = i;
aux[i++].set_long(AT_RANDOM, canary);
kprintf("* Stack protector value: %#lx\n", canary);
// entropy slot
aux[i++].set_ptr(AT_RANDOM, &aux[canary_idx].a_un.a_val);
aux[i++].set_long(AT_NULL, 0);

#if defined(__x86_64__)
PRATTLE("* Initialize syscall MSR (64-bit)\n");
Expand Down
Loading