Closed morphis closed 3 years ago
Confirmed reproduced.
Ah so the apparmor profile is only generated on start, so if its never been started it wont be there.
I'm not sure why we only generated the profile on start though... @stgraber do you know?
@stgraber interesting apparmor.InstanceParse(d.state, d)
is only called in one place, from lxc.Update()
and not in qemu.Update()
so it seems like we could do with standardising the apparmor profile management approach across instance types too.
The lxc.Update()
command will call apparmor.InstanceLoad(d.state, d)
if the container is running and the security.nesting
or raw.apparmor
settings have changed, so maybe that will suffice and we don't need to do InstanceParse
as well earlier in the same function.
We only need the profile on start so we don't spend the time generating it before that. The binary profile itself may differ based on apparmor or kernel version so doing it at creation time may end up being a waste of time.
I'm a bit confused as to how this only started being a problem now though.
I'm pretty sure that the check with apparmor.InstanceParse(d.state, d)
isn't doing anything anyway, as it will be checking the old apparmor profile (if it exists) not the new one, so its not doing validation of the modified raw.apparmor
setting anyway.
@stgraber perhaps nobody has initialised and not started a container and then enabled nesting via an update before first boot.
After first boot, the profile will exist, so will parse validation (even though its not actually validating future changes).
If it was in the profile it would be fine, as that wouldn't cause a pre-first-start update.
So that are a few things with update:
@stgraber the apparmor.InstanceLoad(d.state, d)
function seems to rebuild the apparmor profile from the instance config, so I assume that is what we need to be calling when the raw.apparmor
or security.nesting
settings are changed. And I presume this will also end up validating the profile as a side effect so we don't need to call apparmor.InstanceParse(d.state, d)
at all.
However there's a warning sign for me here in that currently for containers the apparmor.InstanceLoad(d.state, d)
function is only called when the container has been started (its called in onStart()
hook and during Update()
but only when the container is running), so I am worried there's some uncommented knowledge wrapped up in there that there's some reason we cannot load the apparmor profile when the container isn't running.
Well, it's more that we shouldn't load it if not running.
LXD loads the profiles in the kernel on start and unloads on stop.
We should rely on Parse for validation and only do Load if we need the running profile updated in the kernel.
@stgraber yep makes sense, thats basically how it is now.
The problem that I can see is that InstanceParse
doesn't appear to actually generate the profile file, it just assumes it exists and tries to parse it. It seems to rely on the InstanceLoad
having been previously run to generate the actual profile file.
Perhaps we need to get InstanceParse
to call instanceProfile
internally (this is what is called from InstanceLoad
and returns the actual profile file) and then write that file out if it has changed from current, so that is can be parsed by runApparmor
.
So basically this bit: https://github.com/lxc/lxd/blob/master/lxd/apparmor/instance.go#L71-L87 Followed by: https://github.com/lxc/lxd/blob/master/lxd/apparmor/instance.go#L117
Ah yeah, we definitely need Parse to generate the profile or if that's too weird, have a separate Validate which does that.
Required information
This is on an amd64 system which got a snap refresh this morning to
installed: 4.15 (20760) 69MB -
Issue description
When initializing a container (but not starting it) setting
security.nesting
fails with an apparmor_parser error failing to find the profile for the container.Starting the container after
lxc init
and beforelxc config set
generates the profile and allows the config item to be set.Steps to reproduce
Information to attach
dmesg
)lxc info NAME --show-log
)lxc config show NAME --expanded
)lxc monitor
while reproducing the issue)