interfaces/apparmor: load unchanged but unloaded profiles #838

Closed
wants to merge 3 commits into
from

Conversation

Projects
None yet
4 participants
Contributor

zyga commented Apr 8, 2016

This patch changes Setup() so that after loading changed profiles
there's a second pass that looks at apparmor profiles actually loaded
into the kernel and loads any profiles missing.

This scenario might happen if the install operation is interrupted after
writing profiles to disk but before loading them into the kernel.

Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com

interfaces/apparmor: load unchanged but unloaded profiles
This patch changes Setup() so that after loading changed profiles
there's a second pass that looks at apparmor profiles actually loaded
into the kernel and loads any profiles missing.

This scenario might happen if the install operation is interrupted after
writing profiles to disk but before loading them into the kernel.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Apr 8, 2016

Pinging @jdstrand for a review

interfaces/apparmor/backend_test.go
+ snapInfo := s.installSnap(c, developerMode, sambaYamlV1)
+ profile := filepath.Join(dirs.SnapAppArmorDir, "snap.samba.smbd")
+ // Forget all loaded profiles
+ err := ioutil.WriteFile(s.profilesFilename, nil, 0655)
@jdstrand

jdstrand Apr 8, 2016

Contributor

0644?

@zyga

zyga Apr 8, 2016

Contributor

This is just a test but fair enough :-)

Contributor

jdstrand commented Apr 8, 2016

I think you may have typoed 0655 and meant 0644.

This looks fine codewise and what it is doing with the profiles. I wonder though, what if Setup() gets interrupted in this part of the code. Will it be run again at a later time?

LGTM so long as the typo is fixed and if Setup() is working as designed.

Contributor

zyga commented Apr 8, 2016

@jdstrand yes, it will be re-tried the next time snappy boots

interfaces/apprmor: use 0644 in tests files
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Member

chipaca commented Apr 12, 2016

This LGTM, but seems to suffer from a bad case of moving code around without running the tests after.

+ }
+ // Sanity checking, see if all the profiles are really loaded and load
+ // those profiles that are not. This can happen if the files were on disk
+ // but were not really loaded (e.g. due to an interrupted install).
@niemeyer

niemeyer Apr 12, 2016

Contributor

What happens if the profile is already loaded, is written down to disk, changed, but then not reloaded? It will not be reloaded above, nor below. Sounds like we're going over a lot of trouble with reading files back, re-verifying that things are indeed loaded, and still have the potential for easy bugs.

Can we instead change the approach so it is simpler and thus harder to fail?

@zyga

zyga Apr 12, 2016

Contributor

Without patching apparmor to give us cryptographic hashes of the loaded profile we are always going to be in a hard place. We could unload all profiles but that will quickly bite us as those things are slow to compute.

@jdstrand What do you think?

@jdstrand

jdstrand Apr 12, 2016

Contributor

I previously mentioned that I had a hard time understanding the purpose of this addition. We are invoking the parser in such a way that you point it at a policy file, it compiles it into a cache file and loads it into the kernel. If the cache file doesn't exist on reboot, the parser will create it; if it does exist and is newer than the profile, the parser will use the cache file; if it does exist but is older than the profile, the parser will recompile and create a new cache file. Snappy should continue with this approach.

Therefore, all you need to do is make sure all the profiles you want are created and then run the parser on them (obviously checking for errors; but also don't update the mtime unless they actually changed). If things get interrupted on what would otherwise be a successful parser run, don't invalidate the cache files you already computed, just run the parser on them in the way you always would (reloading an already loaded profile from cache is cheap, fast and robust).

@zyga

zyga Apr 13, 2016

Contributor

@jdstrand this is exactly what this patch is doing. The tricky part is part is that apparmor backend code only loads / unloads profiles in reaction changes to profiles on disk. If you interrupt the current code at the right time then there will be no disk changes when the task is re-tried.

Thinking about it now I think I will unconditionally load all profiles. This will take care of apparmor include file changes (apparmor_parser -p discussion from the email thread) and will be a simple thing to do before we invest in a more efficient version.

@niemeyer

niemeyer Apr 13, 2016

Contributor

No, this is not actually what the patched code is doing. The code does a complex dance trying to observe what actually changed, and then makes it even more complex by observing if any of the files on disk are not loaded.

What we should do instead, is to load everything the logic might possibly have changed. I suspect that's going to be much simpler, more robust, and perhaps even faster, ironically, since we won't be re-reading stuff from disk.

@niemeyer niemeyer added the Reviewed label Apr 12, 2016

Contributor

zyga commented Apr 12, 2016

@chipaca the elusive simplicity of github's update button

Contributor

zyga commented Apr 13, 2016

I'm closing this for now as I plan to use a more reliable method that solves other problems while being simpler overall.

@zyga zyga closed this Apr 13, 2016

@zyga zyga deleted the zyga:ifaces-apparmor-loading branch Apr 13, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment