random: always use the PRNG, and use entropy sources to feed it

remove the yarrow module. the hardware modules can push entropy with queue_randomness().
virtio_rng will now push entropy every 300 seconds.
helps with #14937

Change-Id: If76c5deabf61dc616a0e051332f44b89deb6b8a1
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5824
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Jérôme Duval
2022-11-21 18:28:41 +00:00
committed by waddlesplash
parent 0843085384
commit 34e9243872
8 changed files with 157 additions and 252 deletions
+2 -8
View File
@@ -14,18 +14,12 @@
typedef struct { typedef struct {
driver_module_info info; driver_module_info info;
status_t (*queue_randomness)(uint64 value);
} random_for_controller_interface; } random_for_controller_interface;
#define RANDOM_FOR_CONTROLLER_MODULE_NAME "bus_managers/random/controller/driver_v1" #define RANDOM_FOR_CONTROLLER_MODULE_NAME "bus_managers/random/controller/driver_v1"
// Bus manager interface used by Random controller drivers.
typedef struct random_module_info {
driver_module_info info;
status_t (*read)(void* cookie, void *_buffer, size_t *_numBytes);
status_t (*write)(void* cookie, const void *_buffer, size_t *_numBytes);
} random_module_info;
#endif /* _RANDOM_H */ #endif /* _RANDOM_H */
@@ -34,7 +34,6 @@
static mutex sRandomLock; static mutex sRandomLock;
static random_module_info *sRandomModule;
static void *sRandomCookie; static void *sRandomCookie;
device_manager_info* gDeviceManager; device_manager_info* gDeviceManager;
@@ -44,6 +43,15 @@ typedef struct {
} random_driver_info; } random_driver_info;
static status_t
random_queue_randomness(uint64 value)
{
MutexLocker locker(&sRandomLock);
RANDOM_ENQUEUE(value);
return B_OK;
}
// #pragma mark - device module API // #pragma mark - device module API
@@ -74,7 +82,7 @@ random_read(void *cookie, off_t position, void *_buffer, size_t *_numBytes)
TRACE("read(%Ld,, %ld)\n", position, *_numBytes); TRACE("read(%Ld,, %ld)\n", position, *_numBytes);
MutexLocker locker(&sRandomLock); MutexLocker locker(&sRandomLock);
return sRandomModule->read(sRandomCookie, _buffer, _numBytes); return RANDOM_READ(sRandomCookie, _buffer, _numBytes);
} }
@@ -83,11 +91,7 @@ random_write(void *cookie, off_t position, const void *buffer, size_t *_numBytes
{ {
TRACE("write(%Ld,, %ld)\n", position, *_numBytes); TRACE("write(%Ld,, %ld)\n", position, *_numBytes);
MutexLocker locker(&sRandomLock); MutexLocker locker(&sRandomLock);
if (sRandomModule->write == NULL) { return RANDOM_WRITE(sRandomCookie, buffer, _numBytes);
*_numBytes = 0;
return EINVAL;
}
return sRandomModule->write(sRandomCookie, buffer, _numBytes);
} }
@@ -187,6 +191,7 @@ random_init_driver(device_node *node, void **cookie)
return B_NO_MEMORY; return B_NO_MEMORY;
mutex_init(&sRandomLock, "/dev/random lock"); mutex_init(&sRandomLock, "/dev/random lock");
RANDOM_INIT();
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
@@ -202,6 +207,8 @@ random_uninit_driver(void *_cookie)
{ {
CALLED(); CALLED();
RANDOM_UNINIT();
mutex_destroy(&sRandomLock); mutex_destroy(&sRandomLock);
random_driver_info* info = (random_driver_info*)_cookie; random_driver_info* info = (random_driver_info*)_cookie;
@@ -220,38 +227,10 @@ random_register_child_devices(void* _cookie)
gDeviceManager->publish_device(info->node, "urandom", gDeviceManager->publish_device(info->node, "urandom",
RANDOM_DEVICE_MODULE_NAME); RANDOM_DEVICE_MODULE_NAME);
} }
// add the default Yarrow RNG
device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
{ string: "Yarrow RNG" }},
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
{ string: RANDOM_FOR_CONTROLLER_MODULE_NAME }},
{ NULL }
};
device_node* node;
return gDeviceManager->register_node(info->node,
YARROW_RNG_SIM_MODULE_NAME, attrs, NULL, &node);
}
// #pragma mark -
status_t
random_added_device(device_node *node)
{
CALLED();
status_t status = gDeviceManager->get_driver(node,
(driver_module_info **)&sRandomModule, &sRandomCookie);
return status; return status;
} }
// #pragma mark - // #pragma mark -
@@ -311,11 +290,13 @@ random_for_controller_interface sRandomForControllerModule = {
}, },
NULL, // supported devices NULL, // supported devices
random_added_device, NULL,
NULL, NULL,
NULL, NULL,
NULL NULL
} },
random_queue_randomness,
}; };
@@ -323,6 +304,5 @@ module_info* modules[] = {
(module_info*)&sRandomDriver, (module_info*)&sRandomDriver,
(module_info*)&sRandomDevice, (module_info*)&sRandomDevice,
(module_info*)&sRandomForControllerModule, (module_info*)&sRandomForControllerModule,
(module_info*)&gYarrowRandomModule,
NULL NULL
}; };
@@ -286,10 +286,28 @@ kill_chrand(ch_randgen *randgen)
// #pragma mark - // #pragma mark -
// Random interface
static status_t status_t
yarrow_init()
{
CALLED();
sRandomEnv = new_chrand(8);
if (sRandomEnv == NULL)
return B_NO_MEMORY;
return B_OK;
}
void
yarrow_uninit()
{
CALLED();
kill_chrand(sRandomEnv);
}
status_t
yarrow_rng_read(void* cookie, void *_buffer, size_t *_numBytes) yarrow_rng_read(void* cookie, void *_buffer, size_t *_numBytes)
{ {
if (!IS_USER_ADDRESS(_buffer)) if (!IS_USER_ADDRESS(_buffer))
@@ -323,7 +341,7 @@ yarrow_rng_read(void* cookie, void *_buffer, size_t *_numBytes)
} }
static status_t status_t
yarrow_rng_write(void* cookie, const void *_buffer, size_t *_numBytes) yarrow_rng_write(void* cookie, const void *_buffer, size_t *_numBytes)
{ {
OCTET *buffer = (OCTET*)_buffer; OCTET *buffer = (OCTET*)_buffer;
@@ -342,54 +360,9 @@ yarrow_rng_write(void* cookie, const void *_buffer, size_t *_numBytes)
} }
// #pragma mark - void
yarrow_enqueue_randomness(const uint64 value)
static status_t
yarrow_init_bus(device_node* node, void** bus_cookie)
{ {
CALLED(); CALLED();
sRandomEnv = new_chrand(8); chseed(sRandomEnv, value);
if (sRandomEnv == NULL)
return B_NO_MEMORY;
return B_OK;
} }
static void
yarrow_uninit_bus(void* bus_cookie)
{
CALLED();
kill_chrand(sRandomEnv);
}
static void
yarrow_bus_removed(void* bus_cookie)
{
return;
}
// #pragma mark -
random_module_info gYarrowRandomModule = {
{
{
YARROW_RNG_SIM_MODULE_NAME,
0,
NULL
},
NULL, // supports_device,
NULL, // register_device,
yarrow_init_bus,
yarrow_uninit_bus,
NULL, // register child devices
NULL, // rescan
yarrow_bus_removed,
},
yarrow_rng_read,
yarrow_rng_write
};
@@ -14,15 +14,23 @@
#include "random.h" #include "random.h"
#define YARROW_RNG_SIM_MODULE_NAME "bus_managers/random/yarrow_rng/device/v1"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
status_t yarrow_init();
void yarrow_uninit();
void yarrow_enqueue_randomness(const uint64 value);
extern random_module_info gYarrowRandomModule; status_t yarrow_rng_read(void* cookie, void *_buffer, size_t *_numBytes);
status_t yarrow_rng_write(void* cookie, const void *_buffer, size_t *_numBytes);
#define RANDOM_INIT yarrow_init
#define RANDOM_UNINIT yarrow_uninit
#define RANDOM_ENQUEUE yarrow_enqueue_randomness
#define RANDOM_READ yarrow_rng_read
#define RANDOM_WRITE yarrow_rng_write
#ifdef __cplusplus #ifdef __cplusplus
@@ -24,24 +24,19 @@ get_feature_name(uint32 feature)
VirtioRNGDevice::VirtioRNGDevice(device_node *node) VirtioRNGDevice::VirtioRNGDevice(device_node *node)
: :
fNode(node),
fVirtio(NULL), fVirtio(NULL),
fVirtioDevice(NULL), fVirtioDevice(NULL),
fStatus(B_NO_INIT), fStatus(B_NO_INIT),
fOffset(BUFFER_SIZE), fExpectsInterrupt(false),
fExpectsInterrupt(false) fDPCHandle(NULL)
{ {
CALLED(); CALLED();
B_INITIALIZE_SPINLOCK(&fInterruptLock); B_INITIALIZE_SPINLOCK(&fInterruptLock);
fInterruptCondition.Init(this, "virtio rng transfer"); fInterruptCondition.Init(this, "virtio rng transfer");
get_memory_map(fBuffer, BUFFER_SIZE, &fEntry, 1);
// get the Virtio device from our parent's parent // get the Virtio device from our parent's parent
device_node *parent = gDeviceManager->get_parent_node(node); device_node *virtioParent = gDeviceManager->get_parent_node(node);
device_node *virtioParent = gDeviceManager->get_parent_node(parent);
gDeviceManager->put_node(parent);
gDeviceManager->get_driver(virtioParent, (driver_module_info **)&fVirtio, gDeviceManager->get_driver(virtioParent, (driver_module_info **)&fVirtio,
(void **)&fVirtioDevice); (void **)&fVirtioDevice);
@@ -68,11 +63,31 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus)); ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus));
return; return;
} }
fStatus = gDPC->new_dpc_queue(&fDPCHandle, "virtio_rng timer",
B_LOW_PRIORITY);
if (fStatus != B_OK) {
ERROR("dpc setup failed (%s)\n", strerror(fStatus));
return;
}
if (fStatus == B_OK) {
fTimer.user_data = this;
fStatus = add_timer(&fTimer, &HandleTimerHook, 300 * 1000 * 1000, B_PERIODIC_TIMER);
if (fStatus != B_OK)
ERROR("timer setup failed (%s)\n", strerror(fStatus));
}
// trigger also now
gDPC->queue_dpc(fDPCHandle, HandleDPC, this);
} }
VirtioRNGDevice::~VirtioRNGDevice() VirtioRNGDevice::~VirtioRNGDevice()
{ {
cancel_timer(&fTimer);
gDPC->delete_dpc_queue(fDPCHandle);
} }
@@ -84,46 +99,42 @@ VirtioRNGDevice::InitCheck()
status_t status_t
VirtioRNGDevice::Read(void* _buffer, size_t* _numBytes) VirtioRNGDevice::_Enqueue()
{ {
CALLED(); CALLED();
if (fOffset >= BUFFER_SIZE) { uint64 value = 0;
{ physical_entry entry;
InterruptsSpinLocker locker(fInterruptLock); get_memory_map(&value, sizeof(value), &entry, 1);
fExpectsInterrupt = true;
fInterruptCondition.Add(&fInterruptConditionEntry);
}
status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &fEntry,
NULL);
if (result != B_OK) {
ERROR("queueing failed (%s)\n", strerror(result));
return result;
}
result = fInterruptConditionEntry.Wait(B_CAN_INTERRUPT); {
InterruptsSpinLocker locker(fInterruptLock);
{ fExpectsInterrupt = true;
InterruptsSpinLocker locker(fInterruptLock); fInterruptCondition.Add(&fInterruptConditionEntry);
fExpectsInterrupt = false; }
} status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &entry, NULL);
if (result != B_OK) {
if (result == B_OK) { ERROR("queueing failed (%s)\n", strerror(result));
fOffset = 0; return result;
} else if (result != B_INTERRUPTED) {
ERROR("request failed (%s)\n", strerror(result));
}
} }
if (fOffset < BUFFER_SIZE) { result = fInterruptConditionEntry.Wait(B_CAN_INTERRUPT);
size_t size = min_c(BUFFER_SIZE - fOffset, *_numBytes);
if (user_memcpy(_buffer, fBuffer + fOffset, size) != B_OK) {
return B_BAD_ADDRESS; InterruptsSpinLocker locker(fInterruptLock);
fOffset += size; fExpectsInterrupt = false;
*_numBytes = size; }
} else
*_numBytes = 0; if (result == B_OK) {
return B_OK; if (value != 0) {
gRandom->queue_randomness(value);
TRACE("enqueue %" B_PRIx64 "\n", value);
}
} else if (result != B_OK && result != B_INTERRUPTED) {
ERROR("request failed (%s)\n", strerror(result));
}
return result;
} }
@@ -145,3 +156,22 @@ VirtioRNGDevice::_RequestInterrupt()
SpinLocker locker(fInterruptLock); SpinLocker locker(fInterruptLock);
fInterruptCondition.NotifyAll(); fInterruptCondition.NotifyAll();
} }
/*static*/ int32
VirtioRNGDevice::HandleTimerHook(struct timer* timer)
{
VirtioRNGDevice* device = reinterpret_cast<VirtioRNGDevice*>(timer->user_data);
gDPC->queue_dpc(device->fDPCHandle, HandleDPC, device);
return B_HANDLED_INTERRUPT;
}
/*static*/ void
VirtioRNGDevice::HandleDPC(void *arg)
{
VirtioRNGDevice* device = reinterpret_cast<VirtioRNGDevice*>(arg);
device->_Enqueue();
}
@@ -7,6 +7,7 @@
#include <condition_variable.h> #include <condition_variable.h>
#include <dpc.h>
#include <lock.h> #include <lock.h>
#include "random.h" #include "random.h"
#include <virtio.h> #include <virtio.h>
@@ -24,9 +25,7 @@
extern device_manager_info* gDeviceManager; extern device_manager_info* gDeviceManager;
extern random_for_controller_interface *gRandom; extern random_for_controller_interface *gRandom;
extern dpc_module_info *gDPC;
#define BUFFER_SIZE 16
class VirtioRNGDevice { class VirtioRNGDevice {
@@ -36,15 +35,15 @@ public:
status_t InitCheck(); status_t InitCheck();
status_t Read(void* buffer, size_t* numBytes); protected:
static int32 HandleTimerHook(struct timer* timer);
static void HandleDPC(void* arg);
private: private:
static void _RequestCallback(void* driverCookie, static void _RequestCallback(void* driverCookie,
void *cookie); void *cookie);
void _RequestInterrupt(); void _RequestInterrupt();
status_t _Enqueue();
device_node* fNode;
virtio_device_interface* fVirtio; virtio_device_interface* fVirtio;
virtio_device* fVirtioDevice; virtio_device* fVirtioDevice;
@@ -53,14 +52,13 @@ private:
uint32 fFeatures; uint32 fFeatures;
::virtio_queue fVirtioQueue; ::virtio_queue fVirtioQueue;
physical_entry fEntry;
uint8 fBuffer[BUFFER_SIZE];
uint32 fOffset;
spinlock fInterruptLock; spinlock fInterruptLock;
ConditionVariable fInterruptCondition; ConditionVariable fInterruptCondition;
ConditionVariableEntry fInterruptConditionEntry; ConditionVariableEntry fInterruptConditionEntry;
bool fExpectsInterrupt; bool fExpectsInterrupt;
timer fTimer;
void* fDPCHandle;
}; };
+19 -97
View File
@@ -19,47 +19,7 @@
device_manager_info *gDeviceManager; device_manager_info *gDeviceManager;
random_for_controller_interface *gRandom; random_for_controller_interface *gRandom;
dpc_module_info *gDPC;
// #pragma mark - Random module interface
static status_t
sim_init_bus(device_node *node, void **_cookie)
{
CALLED();
VirtioRNGDevice *device = new(std::nothrow)
VirtioRNGDevice(node);
if (device == NULL)
return B_NO_MEMORY;
status_t status = device->InitCheck();
if (status < B_OK) {
delete device;
return status;
}
*_cookie = device;
return B_OK;
}
static void
sim_uninit_bus(void *cookie)
{
CALLED();
VirtioRNGDevice *device = (VirtioRNGDevice*)cookie;
delete device;
}
static status_t
sim_read(void* cookie, void *_buffer, size_t *_numBytes)
{
VirtioRNGDevice *device = (VirtioRNGDevice*)cookie;
return device->Read(_buffer, _numBytes);
}
// #pragma mark - Driver module interface // #pragma mark - Driver module interface
@@ -107,77 +67,39 @@ static status_t
virtio_rng_init_driver(device_node *node, void **_cookie) virtio_rng_init_driver(device_node *node, void **_cookie)
{ {
CALLED(); CALLED();
*_cookie = node; VirtioRNGDevice *device = new(std::nothrow) VirtioRNGDevice(node);
if (device == NULL)
return B_NO_MEMORY;
status_t status = device->InitCheck();
if (status < B_OK) {
delete device;
return status;
}
*_cookie = device;
return B_OK; return B_OK;
} }
static status_t static void
virtio_rng_register_child_devices(void *cookie) virtio_rng_uninit_driver(void *cookie)
{ {
CALLED(); VirtioRNGDevice *device = (VirtioRNGDevice*)cookie;
device_node *node = (device_node *)cookie; delete device;
device_attr attrs[] = {
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
{ string: RANDOM_FOR_CONTROLLER_MODULE_NAME }},
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
{ string: VIRTIO_RNG_CONTROLLER_PRETTY_NAME }},
{ NULL }
};
return gDeviceManager->register_node(node,
VIRTIO_RNG_DEVICE_MODULE_NAME, attrs, NULL, NULL);
} }
static status_t
std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
static random_module_info sVirtioRNGDeviceInterface = {
{
{
VIRTIO_RNG_DEVICE_MODULE_NAME,
0,
std_ops
},
NULL, // supported devices
NULL, // register node
sim_init_bus,
sim_uninit_bus,
NULL, // register child devices
NULL, // rescan
NULL // bus_removed
},
sim_read,
NULL // write
};
static driver_module_info sVirtioRNGDriver = { static driver_module_info sVirtioRNGDriver = {
{ {
VIRTIO_RNG_DRIVER_MODULE_NAME, VIRTIO_RNG_DRIVER_MODULE_NAME,
0, 0,
std_ops NULL
}, },
virtio_rng_supports_device, virtio_rng_supports_device,
virtio_rng_register_device, virtio_rng_register_device,
virtio_rng_init_driver, virtio_rng_init_driver,
NULL, // uninit_driver, virtio_rng_uninit_driver,
virtio_rng_register_child_devices, NULL,
NULL, // rescan NULL, // rescan
NULL, // device_removed NULL, // device_removed
}; };
@@ -186,12 +108,12 @@ static driver_module_info sVirtioRNGDriver = {
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
{ RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info **)&gRandom }, { RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info **)&gRandom },
{ B_DPC_MODULE_NAME, (module_info **)&gDPC },
{} {}
}; };
module_info *modules[] = { module_info *modules[] = {
(module_info *)&sVirtioRNGDriver, (module_info *)&sVirtioRNGDriver,
(module_info *)&sVirtioRNGDeviceInterface,
NULL NULL
}; };
@@ -1743,6 +1743,7 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
_AddPath(*stack, "bus_managers"); _AddPath(*stack, "bus_managers");
} else if (!generic) { } else if (!generic) {
_AddPath(*stack, "drivers"); _AddPath(*stack, "drivers");
_AddPath(*stack, "busses/virtio");
} else { } else {
// For generic drivers, we only allow busses when the // For generic drivers, we only allow busses when the
// request is more specified // request is more specified
@@ -1756,7 +1757,6 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
_AddPath(*stack, "busses/i2c"); _AddPath(*stack, "busses/i2c");
_AddPath(*stack, "busses/scsi"); _AddPath(*stack, "busses/scsi");
_AddPath(*stack, "busses/random"); _AddPath(*stack, "busses/random");
_AddPath(*stack, "busses/virtio");
_AddPath(*stack, "bus_managers/pci"); _AddPath(*stack, "bus_managers/pci");
} }
break; break;