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 <no-reply+buildbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Jérôme Duval 2022-11-19 18:28:19 +01:00 committed by waddlesplash
parent 0843085384
commit 34e9243872
8 changed files with 157 additions and 252 deletions

View File

@ -14,18 +14,12 @@
typedef struct {
driver_module_info info;
status_t (*queue_randomness)(uint64 value);
} random_for_controller_interface;
#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 */

View File

@ -34,7 +34,6 @@
static mutex sRandomLock;
static random_module_info *sRandomModule;
static void *sRandomCookie;
device_manager_info* gDeviceManager;
@ -44,6 +43,15 @@ typedef struct {
} 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
@ -74,7 +82,7 @@ random_read(void *cookie, off_t position, void *_buffer, size_t *_numBytes)
TRACE("read(%Ld,, %ld)\n", position, *_numBytes);
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);
MutexLocker locker(&sRandomLock);
if (sRandomModule->write == NULL) {
*_numBytes = 0;
return EINVAL;
}
return sRandomModule->write(sRandomCookie, buffer, _numBytes);
return RANDOM_WRITE(sRandomCookie, buffer, _numBytes);
}
@ -187,6 +191,7 @@ random_init_driver(device_node *node, void **cookie)
return B_NO_MEMORY;
mutex_init(&sRandomLock, "/dev/random lock");
RANDOM_INIT();
memset(info, 0, sizeof(*info));
@ -202,6 +207,8 @@ random_uninit_driver(void *_cookie)
{
CALLED();
RANDOM_UNINIT();
mutex_destroy(&sRandomLock);
random_driver_info* info = (random_driver_info*)_cookie;
@ -220,38 +227,10 @@ random_register_child_devices(void* _cookie)
gDeviceManager->publish_device(info->node, "urandom",
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;
}
// #pragma mark -
@ -311,11 +290,13 @@ random_for_controller_interface sRandomForControllerModule = {
},
NULL, // supported devices
random_added_device,
NULL,
NULL,
NULL,
NULL
}
},
random_queue_randomness,
};
@ -323,6 +304,5 @@ module_info* modules[] = {
(module_info*)&sRandomDriver,
(module_info*)&sRandomDevice,
(module_info*)&sRandomForControllerModule,
(module_info*)&gYarrowRandomModule,
NULL
};

View File

@ -286,10 +286,28 @@ kill_chrand(ch_randgen *randgen)
// #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)
{
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)
{
OCTET *buffer = (OCTET*)_buffer;
@ -342,54 +360,9 @@ yarrow_rng_write(void* cookie, const void *_buffer, size_t *_numBytes)
}
// #pragma mark -
static status_t
yarrow_init_bus(device_node* node, void** bus_cookie)
void
yarrow_enqueue_randomness(const uint64 value)
{
CALLED();
sRandomEnv = new_chrand(8);
if (sRandomEnv == NULL)
return B_NO_MEMORY;
return B_OK;
chseed(sRandomEnv, value);
}
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
};

View File

@ -14,15 +14,23 @@
#include "random.h"
#define YARROW_RNG_SIM_MODULE_NAME "bus_managers/random/yarrow_rng/device/v1"
#ifdef __cplusplus
extern "C" {
#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

View File

@ -24,24 +24,19 @@ get_feature_name(uint32 feature)
VirtioRNGDevice::VirtioRNGDevice(device_node *node)
:
fNode(node),
fVirtio(NULL),
fVirtioDevice(NULL),
fStatus(B_NO_INIT),
fOffset(BUFFER_SIZE),
fExpectsInterrupt(false)
fExpectsInterrupt(false),
fDPCHandle(NULL)
{
CALLED();
B_INITIALIZE_SPINLOCK(&fInterruptLock);
fInterruptCondition.Init(this, "virtio rng transfer");
get_memory_map(fBuffer, BUFFER_SIZE, &fEntry, 1);
// get the Virtio device from our parent's parent
device_node *parent = gDeviceManager->get_parent_node(node);
device_node *virtioParent = gDeviceManager->get_parent_node(parent);
gDeviceManager->put_node(parent);
device_node *virtioParent = gDeviceManager->get_parent_node(node);
gDeviceManager->get_driver(virtioParent, (driver_module_info **)&fVirtio,
(void **)&fVirtioDevice);
@ -68,11 +63,31 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus));
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()
{
cancel_timer(&fTimer);
gDPC->delete_dpc_queue(fDPCHandle);
}
@ -84,46 +99,42 @@ VirtioRNGDevice::InitCheck()
status_t
VirtioRNGDevice::Read(void* _buffer, size_t* _numBytes)
VirtioRNGDevice::_Enqueue()
{
CALLED();
if (fOffset >= BUFFER_SIZE) {
{
InterruptsSpinLocker locker(fInterruptLock);
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;
}
uint64 value = 0;
physical_entry entry;
get_memory_map(&value, sizeof(value), &entry, 1);
result = fInterruptConditionEntry.Wait(B_CAN_INTERRUPT);
{
InterruptsSpinLocker locker(fInterruptLock);
fExpectsInterrupt = false;
}
if (result == B_OK) {
fOffset = 0;
} else if (result != B_INTERRUPTED) {
ERROR("request failed (%s)\n", strerror(result));
}
{
InterruptsSpinLocker locker(fInterruptLock);
fExpectsInterrupt = true;
fInterruptCondition.Add(&fInterruptConditionEntry);
}
status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &entry, NULL);
if (result != B_OK) {
ERROR("queueing failed (%s)\n", strerror(result));
return result;
}
if (fOffset < BUFFER_SIZE) {
size_t size = min_c(BUFFER_SIZE - fOffset, *_numBytes);
if (user_memcpy(_buffer, fBuffer + fOffset, size) != B_OK)
return B_BAD_ADDRESS;
fOffset += size;
*_numBytes = size;
} else
*_numBytes = 0;
return B_OK;
result = fInterruptConditionEntry.Wait(B_CAN_INTERRUPT);
{
InterruptsSpinLocker locker(fInterruptLock);
fExpectsInterrupt = false;
}
if (result == 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);
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();
}

View File

@ -7,6 +7,7 @@
#include <condition_variable.h>
#include <dpc.h>
#include <lock.h>
#include "random.h"
#include <virtio.h>
@ -24,9 +25,7 @@
extern device_manager_info* gDeviceManager;
extern random_for_controller_interface *gRandom;
#define BUFFER_SIZE 16
extern dpc_module_info *gDPC;
class VirtioRNGDevice {
@ -36,15 +35,15 @@ public:
status_t InitCheck();
status_t Read(void* buffer, size_t* numBytes);
protected:
static int32 HandleTimerHook(struct timer* timer);
static void HandleDPC(void* arg);
private:
static void _RequestCallback(void* driverCookie,
void *cookie);
void _RequestInterrupt();
device_node* fNode;
status_t _Enqueue();
virtio_device_interface* fVirtio;
virtio_device* fVirtioDevice;
@ -53,14 +52,13 @@ private:
uint32 fFeatures;
::virtio_queue fVirtioQueue;
physical_entry fEntry;
uint8 fBuffer[BUFFER_SIZE];
uint32 fOffset;
spinlock fInterruptLock;
ConditionVariable fInterruptCondition;
ConditionVariableEntry fInterruptConditionEntry;
bool fExpectsInterrupt;
timer fTimer;
void* fDPCHandle;
};

View File

@ -19,47 +19,7 @@
device_manager_info *gDeviceManager;
random_for_controller_interface *gRandom;
// #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);
}
dpc_module_info *gDPC;
// #pragma mark - Driver module interface
@ -107,77 +67,39 @@ static status_t
virtio_rng_init_driver(device_node *node, void **_cookie)
{
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;
}
static status_t
virtio_rng_register_child_devices(void *cookie)
static void
virtio_rng_uninit_driver(void *cookie)
{
CALLED();
device_node *node = (device_node *)cookie;
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);
VirtioRNGDevice *device = (VirtioRNGDevice*)cookie;
delete device;
}
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 = {
{
VIRTIO_RNG_DRIVER_MODULE_NAME,
0,
std_ops
NULL
},
virtio_rng_supports_device,
virtio_rng_register_device,
virtio_rng_init_driver,
NULL, // uninit_driver,
virtio_rng_register_child_devices,
virtio_rng_uninit_driver,
NULL,
NULL, // rescan
NULL, // device_removed
};
@ -186,12 +108,12 @@ static driver_module_info sVirtioRNGDriver = {
module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
{ RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info **)&gRandom },
{ B_DPC_MODULE_NAME, (module_info **)&gDPC },
{}
};
module_info *modules[] = {
(module_info *)&sVirtioRNGDriver,
(module_info *)&sVirtioRNGDeviceInterface,
NULL
};

View File

@ -1743,6 +1743,7 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
_AddPath(*stack, "bus_managers");
} else if (!generic) {
_AddPath(*stack, "drivers");
_AddPath(*stack, "busses/virtio");
} else {
// For generic drivers, we only allow busses when the
// request is more specified
@ -1756,7 +1757,6 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
_AddPath(*stack, "busses/i2c");
_AddPath(*stack, "busses/scsi");
_AddPath(*stack, "busses/random");
_AddPath(*stack, "busses/virtio");
_AddPath(*stack, "bus_managers/pci");
}
break;