You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To facilitate #4381, I need a way for device-vat-admin to pass capdata into the kernel endowment through a path that will translate the device-side slots (drefs) into kernel-side ones (krefs). The current endowment mechanism just gives the device a kernel function to call (like getBundle or pushCreateVatIDEvent), but the kernel function does not know which device is calling it, and does not have access to the deviceTranslator.js objects to perform the translation.
This looks a lot like a syscall. Devices can use syscall.sendOnly, which translates dref-to-kref and then pushes a kref-based message onto the run-queue. So I'm thinking I should add a syscall that can invoke pre-arranged "kernel hooks".
Description of the Design
The kernel would configure these for each device by providing a record of named functions. Each function will be called with kref-based capdata. On the device side, a new syscall.callKernelHook is used: it takes a hook name and an argument. deviceManager.js arranges for the syscall to translate the argument into kref space, invoke the given kernel function, then translate any return value back into dref space:
where the kernel-side hook receives and returns (kref-space) capdata. Translation occurs in both directions.
All arguments passed through callKernelHook() must be serializable: devices have access to external "magic" endowment functions, but they should not send these through callKernelHook. The serializer provided by buildSerializationTools will not know what to do with such endowments (it is much more limited than the one used by liveslots).
Security Considerations
Devices are pretty powerful. They're run in their own compartment, but they share an engine with the kernel, so an infinite loop will prevent the kernel from making progress. They are subject to ocap protections (the syscall they receive is hardened and defensive, etc), but if the host application chooses to provide a device with powerful endowments, the device becomes as powerful as those endowments.
These hooks provide a way to limit that power somewhat, at least they provide a data-only interface to things outside the device. It might be interesting to pursue this model for externally-provided endowments (like the Mailbox device getting access to the host-provided storage buffer), and also for input endowments (q.v. #720). I'd set aside the name syscall.callExternalHook or callEndowedHook or something for that path.
Test Plan
Testing this might be tricky. These hooks only make sense for the kernel to configure itself: kref space isn't meaningful outside the kernel (although test functions like controller.queueToKref suggest otherwise). For regular devices, a unit test can configure the device and its endowments in the same way normal host applications would: config.devices and the deviceEndowments that is passed as the second argument to makeSwingsetController(). But if these are only meaningful when provided by the kernel, it would be awkward to introduce a user-visible way to inject them.
The built-in kernel endowments would be limited to vat-admin (indeed that's the primary, and thus far only use case for this feature). And I wouldn't want test functionality to be hanging off a device or endowment that's used in production.
One possibility is to put an addTestDeviceHook property on runtimeOptions. If present, it would be a function that would be used by a hook made available to device-vat-admin.
Another is to add kernel.addDeviceHook(deviceName, hook). Calling this would require access to the kernel object, not just the controller, which matches the pattern used in a handful of unit tests (test-kernel.js among them), and would be hidden from normal userspace.
The text was updated successfully, but these errors were encountered:
I've built this and will file a PR shortly. But in a discussion with @FUDCo about how I'm actually using this to achieve #4381, it occurred to me that an alternative approach would be to implement "kernel-provided device nodes", in which the kernel would set dNN.owner = null to indicate that the kernel owns a device node. So when vat-vat-admin does syscall.callNow(deviceVatAdmin, 'createVat', args), it would get routed to the kernel instead of device-vat-admin (and device-vat-admin would go away).
This would have a lot of benefits over the PR I'm working on:
with no device-vat-admin, userspace is no longer obligated to help the kernel wire up its own internal components
the bootstrap vat no longer has a way to forge newVatCallback or vat-termination messages
the lack of GC in devices no longer causes vatParameter objects to get retained forever
This would not require changes to the code in vat-vat-admin (it will keep making D() calls), but device-vat-admin goes away, userspace bootstrap() functions must change to replace their vatAdminService = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin) with vatAdminService = vats.vatAdmin.
It would require initializeSwingSet to allocate the new kernel-owned device node, and include it in the vatParameters arguments passed to vat-vat-admin, effectively moving the createVatAdminService call into buildRootObject.
Raw devices can use this feature to call kernel functions through a "hook"
that translates device-side slots ("drefs") into kernel-side slots ("krefs").
This will make it possible for devices to submit capdata to kernel endowments
like `pushCreateVatIDEvent`, so vatParameters can carry slots.
closes#4726
Raw devices can use this feature to call kernel functions through a "hook"
that translates device-side slots ("drefs") into kernel-side slots ("krefs").
This will make it possible for devices to submit capdata to kernel endowments
like `pushCreateVatIDEvent`, so vatParameters can carry slots.
closes#4726
What is the Problem Being Solved?
To facilitate #4381, I need a way for
device-vat-admin
to pass capdata into the kernel endowment through a path that will translate the device-side slots (drefs) into kernel-side ones (krefs). The current endowment mechanism just gives the device a kernel function to call (likegetBundle
orpushCreateVatIDEvent
), but the kernel function does not know which device is calling it, and does not have access to thedeviceTranslator.js
objects to perform the translation.This looks a lot like a syscall. Devices can use
syscall.sendOnly
, which translates dref-to-kref and then pushes a kref-based message onto the run-queue. So I'm thinking I should add a syscall that can invoke pre-arranged "kernel hooks".Description of the Design
The kernel would configure these for each device by providing a record of named functions. Each function will be called with kref-based capdata. On the device side, a new
syscall.callKernelHook
is used: it takes a hook name and an argument.deviceManager.js
arranges for the syscall to translate the argument into kref space, invoke the given kernel function, then translate any return value back into dref space:This is the moral equivalent of a vat doing something like
result = D(hooks).add([devNode, presence])
.Within the kernel.js
start
function, the hook would be configured with:where the kernel-side hook receives and returns (kref-space) capdata. Translation occurs in both directions.
All arguments passed through
callKernelHook()
must be serializable: devices have access to external "magic" endowment functions, but they should not send these throughcallKernelHook
. The serializer provided bybuildSerializationTools
will not know what to do with such endowments (it is much more limited than the one used by liveslots).Security Considerations
Devices are pretty powerful. They're run in their own compartment, but they share an engine with the kernel, so an infinite loop will prevent the kernel from making progress. They are subject to ocap protections (the
syscall
they receive is hardened and defensive, etc), but if the host application chooses to provide a device with powerful endowments, the device becomes as powerful as those endowments.These hooks provide a way to limit that power somewhat, at least they provide a data-only interface to things outside the device. It might be interesting to pursue this model for externally-provided endowments (like the Mailbox device getting access to the host-provided storage buffer), and also for input endowments (q.v. #720). I'd set aside the name
syscall.callExternalHook
orcallEndowedHook
or something for that path.Test Plan
Testing this might be tricky. These hooks only make sense for the kernel to configure itself: kref space isn't meaningful outside the kernel (although test functions like
controller.queueToKref
suggest otherwise). For regular devices, a unit test can configure the device and its endowments in the same way normal host applications would:config.devices
and thedeviceEndowments
that is passed as the second argument tomakeSwingsetController()
. But if these are only meaningful when provided by the kernel, it would be awkward to introduce a user-visible way to inject them.The built-in kernel endowments would be limited to vat-admin (indeed that's the primary, and thus far only use case for this feature). And I wouldn't want test functionality to be hanging off a device or endowment that's used in production.
One possibility is to put an
addTestDeviceHook
property onruntimeOptions
. If present, it would be a function that would be used by a hook made available to device-vat-admin.Another is to add
kernel.addDeviceHook(deviceName, hook)
. Calling this would require access to thekernel
object, not just thecontroller
, which matches the pattern used in a handful of unit tests (test-kernel.js
among them), and would be hidden from normal userspace.The text was updated successfully, but these errors were encountered: