Hello Genodians,
I am new to Genode and am looking into projects I might be able to do to help get practice with Genode and get a better understanding of rust. On the last rust update, it seemed like the Genode team determined one of the next steps would be to explore rust on top of native Genode framework. Would there be a project that would be able to help achieve this goal? I thought of working with the Gnode api to create a transition layer so that components written in rust can directly work with the api. Would this be a project be helpful or would something else be more appropriate? Thanks in advance for the help, and if I am off base, please let me know!
Sincerely, Nathan
Hi Nathan,
Thanks for your interest in Genode and Rust!
On the last rust update, it seemed like the Genode team determined one of the next steps would be to explore rust on top of native Genode framework. Would there be a project that would be able to help achieve this goal?
We don't have a clear path towards native Genode components in Rust, because a native Rust Genode API would depend on a Genode ABI (Application Binary Interface), for which we don't have a clear vision yet. Right now, the Genode interfaces are defined by their C++ implementation (supplemented with a Genode C API for the narrow scope of porting device drivers). Therefore adding native Rust bindings would entail defining a Genode ABI so that the Rust API can be implemented independently from the C++ implementation.
I thought of working with the Gnode api to create a transition layer
so that components written in rust can directly work with the api. Would this be a project be helpful or would something else be more appropriate?
Our road map[1] goal of Rust-based components for an email scenario is meant as an opportunity to venture from components that run purely on the libc / POSIX ABI towards incorporating native interfaces. In that, your suggestion goes in the right direction. However, instead of attempting to create a whole transition layer, I would suggest that you approach this from building a specific Genode component. Get the examples from the Genode Foundations book[2] to work if you haven't already, then build a libc-based Rust package with Goa (see [3] for an example) and explore creating the necessary bindings for a native Rust component from there.
Maybe others from the Genode team can share their perspective on this, but from previous discussions within Genode Labs (cf. this mailing list post: [4]), my hunch is that if we build an official Genode Rust API, it will be implemented from scratch on a future Genode ABI. Rust bindings based on Rust's FFI will likely play a role on the path towards this goal, so we welcome you experimenting with this. Just be advised that a sort of "genode-rs" translation layer that is based on a FFI to the C++ API is unlikely to be the long term solution that we at Genode Labs will endorse.
I hope this clarifies our vision for Rust on Genode a bit. Enjoy experimenting!
Best wishes,
Ben
[1] https://genode.org/about/road-map [2] https://genode.org/documentation/genode-foundations/23.05/getting_started/He... [3] https://genodians.org/atopia/2023-10-26-a-first-complex-rust-package [4] https://lists.genode.org/mailman3/hyperkitty/list/users@lists.genode.org/mes...
On Mon, Feb 19, 2024 at 5:43 AM Benjamin Lamowski benjamin.lamowski@genode-labs.com wrote:
Hi Nathan,
Thanks for your interest in Genode and Rust!
On the last rust update, it seemed like the Genode team determined one of the next steps would be to explore rust on top of native Genode framework. Would there be a project that would be able to help achieve this goal?
We don't have a clear path towards native Genode components in Rust, because a native Rust Genode API would depend on a Genode ABI (Application Binary Interface), for which we don't have a clear vision yet. Right now, the Genode interfaces are defined by their C++ implementation (supplemented with a Genode C API for the narrow scope of porting device drivers). Therefore adding native Rust bindings would entail defining a Genode ABI so that the Rust API can be implemented independently from the C++ implementation.
I thought of working with the Gnode api to create a transition layer
so that components written in rust can directly work with the api. Would this be a project be helpful or would something else be more appropriate?
Our road map[1] goal of Rust-based components for an email scenario is meant as an opportunity to venture from components that run purely on the libc / POSIX ABI towards incorporating native interfaces. In that, your suggestion goes in the right direction. However, instead of attempting to create a whole transition layer, I would suggest that you approach this from building a specific Genode component. Get the examples from the Genode Foundations book[2] to work if you haven't already, then build a libc-based Rust package with Goa (see [3] for an example) and explore creating the necessary bindings for a native Rust component from there.
Maybe others from the Genode team can share their perspective on this, but from previous discussions within Genode Labs (cf. this mailing list post: [4]), my hunch is that if we build an official Genode Rust API, it will be implemented from scratch on a future Genode ABI. Rust bindings based on Rust's FFI will likely play a role on the path towards this goal, so we welcome you experimenting with this. Just be advised that a sort of "genode-rs" translation layer that is based on a FFI to the C++ API is unlikely to be the long term solution that we at Genode Labs will endorse.
I hope this clarifies our vision for Rust on Genode a bit. Enjoy experimenting!
Best wishes, Ben
[1] https://genode.org/about/road-map [2] https://genode.org/documentation/genode-foundations/23.05/getting_started/He... [3] https://genodians.org/atopia/2023-10-26-a-first-complex-rust-package [4] https://lists.genode.org/mailman3/hyperkitty/list/users@lists.genode.org/mes...
I must say I was rather pleased and impressed by my initial impressions of the work that Nick Spinale (CC'd) has done on rust-native interfaces within the seL4 ecosystem. In particular, he has illustrated one possible manifestation of what ergonomic APIs might look like in rust for event-driven, capability-oriented, component-based systems, and also proven a viable path with incremental milestones towards an increasingly capable rust-native runtime environment, with sensible layering of dependencies, etc. within a system in somewhat similar spirit to Genode. I highly recommend taking a look for inspiration.
Reasonable entry-points might be: - https://github.com/seL4/rust-sel4 - https://sel4.github.io/rust-sel4/ - https://www.youtube.com/watch?v=jR2i4Y2Aq3o ("Rust Support in seL4 Userspace: Update and Roadmap" -- seL4 summit 2023)
I have wanted to take a deeper look myself, but alas have yet to prioritize doing so.
Regards, Jean-Philippe
Hi Nathan,
thank you for your interest in participation and for asking about areas of interest.
Would there be a project that would be able to help achieve this goal?
In my opinion, the port of the Sequoia-PGP project [1] via Goa's Rust support [2] would be the most appreciated direction. Not only have I high hopes in the future relevance of this particular project, but it also fits perfectly with our ambition to come up with a solution for handling emails directly on Genode by the end of the year. For this, we have the pressing need for OpenPGP. It would be splendid to address this need via the Sequoia-PGP project.
On technical grounds, I think it would be an intriguing topic because it is far from trivial while still being approachable in smaller steps. One could start with test-driving the library primitives, maybe crafting a custom application for checking PGP signatures as a kind of showcase along the way. If that works out well, one could proceed towards making the 'sq' command line tool available, complementing Goa's Unix example. At the advanced stage, one could investigate a way to map the concept of a PGP daemon (think of a virtual smart card) to Genode's concepts.
Succeeding in any of those steps would be a valuable contribution.
[1] https://sequoia-pgp.org/ [2] https://genodians.org/atopia/2023-10-26-a-first-complex-rust-package
Cheers Norman
On Tue, Feb 20, 2024 at 8:14 AM Norman Feske norman.feske@genode-labs.com wrote:
Hi Nathan,
thank you for your interest in participation and for asking about areas of interest.
Would there be a project that would be able to help achieve this goal?
In my opinion, the port of the Sequoia-PGP project [1] via Goa's Rust support [2] would be the most appreciated direction. Not only have I high hopes in the future relevance of this particular project, but it also fits perfectly with our ambition to come up with a solution for handling emails directly on Genode by the end of the year. For this, we have the pressing need for OpenPGP. It would be splendid to address this need via the Sequoia-PGP project.
On technical grounds, I think it would be an intriguing topic because it is far from trivial while still being approachable in smaller steps. One could start with test-driving the library primitives, maybe crafting a custom application for checking PGP signatures as a kind of showcase along the way. If that works out well, one could proceed towards making the 'sq' command line tool available, complementing Goa's Unix example. At the advanced stage, one could investigate a way to map the concept of a PGP daemon (think of a virtual smart card) to Genode's concepts.
Succeeding in any of those steps would be a valuable contribution.
[1] https://sequoia-pgp.org/ [2] https://genodians.org/atopia/2023-10-26-a-first-complex-rust-package
Cheers Norman
Relating to Norman's last point (a 'PGP daemon' or so), it is perhaps worth pointing out the "split GPG" functionality of Qubes OS for reference and potential inspiration: - https://www.qubes-os.org/doc/split-gpg/ - https://github.com/QubesOS/qubes-app-linux-split-gpg - https://github.com/QubesOS/qubes-app-linux-split-gpg2
The implementation is somewhat tightly coupled to GnuPG and either its command-line interface (for version 1) or agent protocol (for version 2). So, it's not necessarily a useful reference from an implementation perspective if aiming for non-GnuPG implementations of PGP, but perhaps still useful from a conceptual and user-experience perspective. The implementation is admittedly undesirably fragile in ways that I don't think anyone particularly likes (for example the command-filtering approach taken in version 1 is brittle when considering the (sometimes latent) complexity of the GnuPG command line interface, which has resulted in real vulns [1]), but it has been useful to many users while nothing better / practical existed.
[1]: https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-071-2021.txt
The rest of this email provides some (perhaps premature) unsolicited advice of lessons learned while working on the above, offered in the hope that we might collectively avoid repeating what I perceive to be certain mistakes leading to unfortunate consequences in this design space. If I didn't write it up now, it's unlikely I would have later, and am unlikely to be following subsequent implementation discussions to bring it up at a more timely point, so, here it is... Feel free to skip and ignore until/unless relevant.
If there's one thing I wish would have been done differently, especially in the design of the GnuPG agent protocol used in version 2, it would have been to make it easier to add appropriate hooks to be able to inspect the content of a message about to be signed and confirm user intent. By this I mean not only intent to make some arbitrary/unknown signature at a given moment, but rather intent to sign a specific message content, as confirmed in a trustworthy manner, before any signature is made. Trying to have such explicit confirmation at all doesn't necessarily make sense for every use case. For many use cases, it would just be useless noise and lead to decision fatigue and bad UX. However, if you do want to support any use cases where this is desirable, then it is made much easier if the following is considered from the beginning: When designing the protocol / interface between a less-trusted cryptographic-operation-requesting client and a more-trusted back-end key-using agent, then it is desirable to either send the entire message rather than only its hash, or, if only sending its hash (for reasons of size, opaque binary formats, or whatever the case may be), then to still provide a (hopefully convenient and reliable) way to obtain the contents of the message corresponding to said hash. GnuPG's agent protocol (at least last I checked) only sent hashes of messages when requesting signatures, not the message itself [2]. It is much easier and more maintainable to expose the full information an agent may wish to use over a client-independent interface/protocol (such as that which needs to exist anyway if the operation is being performed across a trust boundary) rather than end up needing to patch every potential client of said protocol to expose the same additional information (the message to be signed) out-of-band.
[2]: https://www.gnupg.org/documentation/manuals/gnupg/Agent-PKSIGN.html
OpenSSH has done a better job at this (from my perspective) than GnuPG, in the design of the SSH agent protocol [3][4]. The OpenSSH ssh-agent implementation [5] has long had functionality to be able to require explicit user confirmation before a key is used [6], however, the authors also acknowledge that this is of limited utility and easy to phish. This means that agent forwarding has, for most of its existence, been nearly impossible to expose/enable/use in anything resembling a safe manner... that is, until recently, when they added extensions to be able to restrict how a forwarded agent may be used [7]. This is only possible because the agent actually sees the full message of what it is trying to sign, and can inspect it [8], and do useful things with that information like ask the user to confirm with an explicit trustworthy indication of what user / host identity it's trying to sign a request regarding (at least it could be done, even if it isn't plumbed through to any UI yet [9]), or make the agent aware of forwarding and use it for automated authorization constraints without user involvement (already today in practice). These things would not be possible (or at least, would require additional plumbing and be much harder) if the agent only ever saw a hash of the message it's supposed to sign rather than the message itself. Note that any such message inspection certainly does not need to be done in the same process as what's holding the keys, and arguably it shouldn't be (due to risk of parsing / processing the message potentially leading to exploitation of the agent). Fortunately, having any such domain-specific message inspection (and perhaps rendering, etc.) be delegated to a separate pluggable privilege-separated component[s] feels more natural in Genode than perhaps anything else.
[3]: https://tools.ietf.org/html/draft-miller-ssh-agent [4]: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.agent [5]: https://github.com/openssh/openssh-portable/blob/master/ssh-agent.c [6]: https://man.openbsd.org/ssh-add#c [7]: https://www.openssh.com/agent-restrict.html [8]: https://github.com/openssh/openssh-portable/blob/V_9_6_P1/ssh-agent.c#L676-L... [9]: https://github.com/openssh/openssh-portable/blob/V_9_6_P1/ssh-agent.c#L882
Regards, Jean-Philippe