 Okay. I want to talk today about how we approached the topic of the virtual file system in G-Node. So it's not an academic talk, it's just an experience report what we did and what was our experiences. So, and the talk has four parts. I first want to give a motivation. Why did we took at this topic? Why have you had to look at the virtual file system? Because it's not so natural to take this task in a micro-connist system that is structured like G-Node. So, and the second part I will give the first steps we did and how the system evolved. And in the third part I will describe our current state of the implementation and what we can do with the virtual file system in G-Node. And in the end I will give an outlook and present some ideas how to go on. So, and the starting point for us with our G-Node system was if we implement an operating system, it does not make any sense, it's not of much use if we don't have applications on top of it. We want to use our known applications from the system we came from, it was mostly Linux. And we also want to have our beloved tools in the shell and interact with the system in a normal way. So, how could we come to this state that we have the applications on top of the operating system? So, and the key element is to use open source applications so we can just look at the code, tweak it in some places and port it on top of the G-Node system. And later on we could also have a more detailed look into the components, analyze them and do some security-oriented decomposition of the system of the applications and colonelize some sensitive parts out of complex big applications that should hold all security properties. But the big but is that it's not very appealing to look at really complex components. So, one complex component many people are using is the Thunderbird mail client and it's really complex in its source code itself and it's also using very complex libraries and who wants to look at this source code and try to decompose it. You just want to use it as it is and then try to build a secure system around it and make it better in that way. So, the observation was that these traditional applications that don't get really ported to G-Node get decomposed into smaller components, these traditional applications will prevail, they will always be around. So, now we have this situation that we have the genome system which has a system structure that is very different from the original POSIX environment. So, what does it mean that the application runs in a POSIX environment? What are the requirements? So, we had to look at it and analyze that one first big property of the system that must always be there is that the application has a fairly global view on the resources of the system. You'll always expect that there is a global tree of directories and fires where the resources of the system can be accessed and those resources are also very different in nature. It's not only the data on the storage, the fires we know of like pictures or emails, it's also configuration data that is in fires and to some extent also hardware peripherals are accessed via fires. And even the graphic user interface is based on the file-based access to its resources and additional points were that all those applications know of the POSIX world in the sense of there is only traditional access control. Not that there are administrative tools that change access to resources but also that they try to be robust if the user does something that's not expected like assessing a file with writing to a file that has only permissions. And also these applications need a C or C++ runtime. The C library is the basic layer that's below almost all applications in a POSIX system. And what we also saw at this time was that the POSIX library is really huge. So it cannot be grasped easily in its entireness and on the other hand the applications are only using a small share. So we had someone somehow to identify what is used by the applications from the system API so that they can be ported on top of the genome system. So the genome system on the other hand is very different and that comes down to three points. It's microkernel-based. It's very different from a monolithic system so the microkernel does not provide any abstractions that are not needed. So we have no file system in the kernel. The genome system is also capability-based which means mostly that we don't have a global namespace. As I said before for the POSIX applications they depend on the global view, on the resources that are used. We don't have that in the genome system. We don't want that in the genome system because of the security considerations you have to take if you introduce a global view on the resources. In the capability-based system like genodes we also have fine-grained access control. We have object capabilities that can be delegated to components in a very fine-grained way. We not only have files with permissions, it's more like an evolving system if the access permissions are delegated to the system. The third point is that genode is a component-based system. And with genode we want to keep up this notion of components. Components should not be too complex. It should be software applications or services that can be analyzed if they hold up their security properties and if they do their job like they expected to do. And although these components in the genome system can be combined, how the use case needs it. So a router implementation needs very different system structure than a PC like I'm using here for the talk. And so we want to provide a system where the system integrator can put the brakes of the system and plug them together and have a system that only does what is needed for the use case. And in the end it's always the system, the software complexity that introduces bugs and also security holes into the system. And so we think it's important to keep the software complexity as low as possible. And then comparing those two systems, the original POSIC environment and also the genome system, it sounds like a viable approach to just take the POSIC application and put it in a sandbox. So the coarse grained kind of sandbox could be a kind of virtual machine or a para-virtualized system, but there are also other means like we did. We just approached the, we took the approach to customize the C-Library. We take the application on top of the genome system and try to recompile it with a customized C-Library. So that's not everything that does not fulfill any requirement application has. We also need some more elements of a runtime environment and one element is the virtual file system. So the application can access resources like it's used to. So, and that is also the point. The application now runs in a component, in a micro-corner system, and there is the traditional, just functions like read, write and open and a simple file system implementation. But this must somehow connect, be connected to the outside world, to the genome system. So we have to find a way to connect the libc backend to genome services. And that's the point we started. We implemented a backend for a subset of the libc functions, literally the subset of the first applications we wanted to port. So, and these were only a dozen or two dozen functions. And then we added some small tweaks or hacks to emulate some mechanisms that were expected by the applications. So it gets in a run over state and we could make our practical experiences. And starting from this state, we could extend the C library by the mentioned connection to the genome services. And to achieve that, we introduced a kind of plug-in structure into the C library so that the C library could be extended on start time by shared libraries that implemented plug-ins that wrapped or that adapt the C library to genome services. And here's a list of the first plug-ins we implemented. So we ported some simple file system implementations into libraries on top of genodes, linked them to the application and only connected the block accesses to the block service of the system. So the application could use exclusively a partition of the hard disk, maybe. We also ported network stacks like the lightweight IP stack or also a version of the Linux IP stack on top of genodes that was co-located to the application as a library and connected just to the network interface. We also did some experiments with graphics that's depicted at the bottom here. And the libc plug-in interface helped us much in this case so we could just link together more complicated stuff like ported version of the Gallium graphic stack on the lib-DRM interface and connect to a graphics driver on top of genodes. And this is a picture of how it looked like at that time. So we have an application at the very top that is almost not changed to run on genodes because it's only using the FreeBSD port of the libc library and then we plug it at the bottom, our plug-ins in this case for access to files on a FAT file system. And that's the whole component the application is running in. And then we have a microkernel or genode primitives at accession to a block service that connects the application to the block device driver in this case. Now it's also possible to implement the files in the component on top of the microkernel that sounds like the more natural way. So in this case we need another plug-in for the same application that does not connect to the block service but to the file system service which in turn then uses the block device driver at the bottom. And that depicts one of our goals. The integrator of the system can choose how to structure its system, how the application should be connected to the services and how big the component should be. So then we had some first applications running on top of genodes like the NetPerf server to test the network implementation or some small other components. But what we are missing are our beloved tools, our traditional working environment with the shell and the Unix tools and all that stuff. So we started a new development so-called NUX runtime for Unix software that should enable to also start these simple command line oriented tools on top of genodes. And the nature of those components is that they are spawned by a shell and that they are connected by pipes and run in loops and all that stuff. And what our libc was missing at this time was that processes could start other processes. We did not implement that POSIX feature in the libc because of some hard-to-achieve properties. So we took a different approach, we implemented a simple runtime component for those applications. And the good thing about that is that we could also take those tools in their source code archive form, configure them with the normal configuration tools and build them with their own build system and just link them to our C library and start them on top of the Unix runtime environment. We did not have to adapt in this area. But the difference is now that we don't have one application that has a view on the resources in the system by the connected genodes services. We have a bunch of applications running on top of one runtime that's using a shared resource representation. And this is how it looks like. We still have on top the recompiled application that's using our libc. And now we don't use the plug-in mechanism in the libc to plug a direct wrapper to genodes services like block file system or network. We connect this component to the Unix runtime component. And that's not shown in this picture. Each component of this session runs on the same Unix runtime. So the natural first component that started is a shell. Maybe just imagine that this is the bash program running on top of Unix and that can then instruct the Unix runtime via the session and fork an exit call to spawn its children and also connect them via IO channels. So what's new in Unix is that we did not implement the VFS or file access in a talk way. It was more formalized like a VFS implementation, like a first VFS implementation. We had a library that implemented a framework for a directory tree where we could plug in several features of the VFS, like just mount and tar archive as a subtree of the system. Okay. So after some experience with the Unix runtime environment and the feeling that that is a very big step forward, we thought, okay, now we have this VFS framework. We have several plug-ins inside the Unix runtime. But the problem now is that those bare libc components running on top of Genot cannot profit from the VFC implementation. So we had to move also this implementation into the libc and then share these functionalities between both components. And we could also gradually replace those special libc plug-ins by VFS plug-ins. So we don't have two code bases to maintain. So we can come now back from the resource representation for the Unix runtime to the per-process representation in the VFS instance. And we can now, again, individually configure how one application interacts with the system. And that's also the next part. I want to show you how the VFS is configured in Genot. In Genot, we are using XML to configure our components. It's very easy to parse. We have a very low complexity parser for it. And our components use the same configuration mechanism and share the same code for this. So it's natural to also configure the VFS by XML means. And as you can see here, the VFS is just one sub-node of the component configuration. And the first thing that is needed in the VFS are directories. So you can add a directory node to the VFS and give it a name. And the other plug-ins are then just nodes inside the directory nodes or at the top level. And the nodes, like with the directory node, also the other plug-ins are instantiated based on their name. And the VFS configuration must then be used by Lipsy. So we also have a configuration node for the Lipsy that maps Lipsy mechanisms or functions to the nodes in the VFS. In this case, the standard out and standard error should go to the VFS plug-in. And this is how it would look like completely in one node. And what we gain here is that we have a precise declaration of resource representation in the VFS. So anybody can look at the configuration and see, okay, these resources are available to this component in the system. As I described for the tar plug-in, those plug-ins cannot only implement single files. They can also implement whole directories sub-trees like a tar archive or external file system. And with this in mind, we implemented the feature in the VFS that these nodes are organized as a stack of a file system at one level. So if you have a file system in, maybe you have a file system here in DEAR or two file systems and a node and a file is not found in the first one, you can like in the union mount look in the second one and do a look up there. And the last part is that the VFS configuration and the Lipsy configuration are both two distinct things. And you can just tweak the behavior of the Lipsy library with its own configuration node. So we have a bunch of plug-ins in our VFS implementation. The first one we used is a mapping to our ROM service as a microkernel system that we needed some means to use boot modules in the system and we named them ROM and we can also map nodes in the file system in the VFS to ROM nodes. So like with a directory, a ROM can be given a name in the VFS that must not be the name of the actual boot module. The resource that is looked up in the system is more like is given here in an extra attribute so you can also establish nodes in the system that have another name when looking up the service that implements the session. Mostly for debugging but also for static configuration of systems we included an inlight node where it's possible to just create a file in the VFS that has a fixed content. And also we needed some handy tools for the POSIX applications like the classical def null and zero devices and also we have a simple sim link implementation where you can have a node in the VFS that redirects to another node. And the first important file system we implemented was a local instance of a kind of tempFS, a ROM file system so these applications could generate temporary files and store data in them. I also talked about the Tor node and then we also have these mentioned files to service wrappers that provide genome services directly in one file so we can enable Lipsy applications to get the real-time or use terminus for maybe standard in standard out and also access block devices directly. Like we did with Lipsy in our early developments we also implemented a runtime extension feature of the VFS so it's possible to name nodes in the VFS that are not known to the core implementation and in this case the implementation tries to open shared object files that are linked at runtime to the application and used as custom VFS plugins and we also have some examples in our directivity. The first example is a random generator implementation based on the Jitter entropy of the CPUs that can be used in applications like network applications or we also use it in our Wi-Fi implementation. The second example is a time-based password generator that can just be linked as a file into the VFS. Also important is to connect existing file system services to the application so several Lipsy-based applications can also share one partition of the system and access it. The first attribute is always here depicted the name of the mount so the file system here we have here three file system mount with three distinct names and what I use here is also the label attribute to say okay the file system node that same config should redirect to the resources labeled config and we could also provide local configuration of plugins in those nodes in the case of the file system we can allow or disallow to write to files in the file system. We can also say okay when the file system session is requested from the service just provide a root configuration attribute as we only want to use a subdirectory of the mount of the file system. The important thing to note here is that these configurations are only process local. These are only for the application that's running on G-node and the service itself is configured by other means it uses policies that are provided in the configuration node of the service itself and those look somewhat familiar if one knows the configuration nodes of the file system of the VFS but here the actual properties are enforced like this session that uses this file system is able to write or not to write to the file system and also the visibility can be limited and enforced in the so on. So that is almost the state we are now. There's only one component missing and that's the VFS so on. So that is so much strange. I talked about we want to split in multiple components. We don't want central namespace. Okay. So should I just stop? Yeah, okay. Just keep talking. Yeah, what we now have is a VFS so on. We don't want the global namespace. We want to use the VFS so on as a tool that can also be multi-incentivated in the system. And it's just a tool to use these VFS configurations and share them among several components but that does not mean all components are using the same VFS so on. So yeah, yeah, I don't know. Sorry. So are there any questions? So can the user modify the configuration for tuning of? That depends on the system configuration. So in Gino these configuration files used by applications, by components, by all components are just ROM files and who may change these ROM files at runtime depends on the system policy. So if I implement a service in the system that the user can change several aspects of this configuration, this trusted service could then update the configuration of the components. I think the most complex application, the policy application we are hosting is VirtualBox. But it's not fair to name it on this question because that's a very special case. Yeah, we also have cute applications running on top of Gino. Simple web servers. Yeah, it all depends on the share of the POSIX interface that is used. In some cases you very early on ran into not implemented functions and in some cases it just works out. Okay, thank you.