Confining a general process VM?

I’m looking into building snaps for Neko VM and Haxe. Both of them can act like general virtual machines (the Haxe compiler can be used as an interpreter), which will run user programs, which means I cannot specify the interfaces since they will limit the user programs. So, what is the best practice here?

It is tempting to use the classic policy, but it prevent Ubuntu Core users to install it…

Confining a general-purpose program like this is meaningless. I would argue that both neko and haxe are parts, not actual snaps. I see a few possible approaches:

  • use classic confinement and treat those snaps as developer tools
  • use generic sandbox (no interfaces) and allow those snaps to be content-shared into other snaps (needs discussion as this is an ABI promise that is not allowed by default), they can also double as local developer tools but I’d argue that is of limited use due to confinement
  • don’t make neko/haxe snaps at all, provide high-quality parts to be embedded into other snaps

Depending on their size and ABI guarantees, I’d argue that it could make sense to package as a snap.

If the runtime is exposed via the content interface, then an application using the VM can use it by connecting to that interface. The VM will then run under the application’s confinement policy.

Thanks for the suggestions. I can see that defining a content interface will be useful for creating snaps that depends on the VMs.

I’m more interested in the case of using the snaps for general development, without creating another snap for the user program. Is there a way for a user to override the confinement defined in a snap? e.g. I create a snap that is confinement: strict, and the user may override it to devmode or just enable network if she want to run the VM in someway she want.

You can install a confinement: strict snap with --classic or --devmode. It should work fine with devmode, but you’ve got to be a bit careful with classic mode, since you’ll no longer be running in a separate mount namespace (so libraries under /lib and /usr/lib will now be from the host system rather than the core snap).

With a little effort you can package up a strict confinement snap so it will function in classic mode: the main things to do is to link using an rpath that causes you to look up libraries under /snap/core/current/lib, etc, and possibly pick the runtime dynamic linker from the core snap instead of the host system too.

Is there any reason a user would choose --classic over --devmode? I am wondering if it worth the effort to support.

The main differences from a user perspective are:

  1. --devmode will install the AppArmor policy in complain mode, resulting in extra noise in syslog.
  2. --classic will see the host system’s file system. If you wanted to open a file located outside your home directory while experimenting with an interactive interpreter, that’s going to be a bit difficult in the sandbox’s mount namespace.

In general, --devmode is intended for use when developing a snap. It isn’t a general purpose confinement policy for distributing development tools.

Any strictly confined snap can be installed with devmode by just passing --devmode to snap install.

not if your snap has interfaces, you only get complaints in devmode if interfaces arent existing or are not connected…