Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
cmd/snap-confine: add detection of stale mount namespace #3999
Conversation
codecov-io
commented
Oct 3, 2017
•
Codecov Report
@@ Coverage Diff @@
## master #3999 +/- ##
==========================================
- Coverage 75.8% 75.78% -0.02%
==========================================
Files 433 433
Lines 37174 37293 +119
==========================================
+ Hits 28180 28264 +84
- Misses 7022 7055 +33
- Partials 1972 1974 +2
Continue to review full report at Codecov.
|
jdstrand
reviewed
Oct 3, 2017
As requested, this is only a preliminary review on the approach and it is anot a full review (though I did make a couple small suggestions). I think the approach makes sense: squashfs are looback files that show up as maj:min 7:NN. Therefore, get the maj:min of the current base snap and see if it is mounted in the mount namespace and if it isn't, it is stale. You are comparing both the actual path in /snap/base/rev and the maj:min, which avoids accidentally matching against hostfs.
+1 on the general approach.
| + if (ns_statfs_buf.f_type == NSFS_MAGIC | ||
| + || ns_statfs_buf.f_type == PROC_SUPER_MAGIC) { | ||
| + char fname[PATH_MAX]; | ||
| + char base_snap_rev[PATH_MAX]; |
jdstrand
Oct 3, 2017
Contributor
Can you initialize this to be: char base_snap_rev[PATH_MAX] = { 0, };. You may as well do the same with fname.
| + // Read the revision of the base snap. | ||
| + sc_must_snprintf(fname, sizeof fname, "%s/%s/current", | ||
| + SNAP_MOUNT_DIR, base_snap_name); | ||
| + if (readlink(fname, base_snap_rev, sizeof base_snap_rev) < 0) { |
jdstrand
Oct 3, 2017
Contributor
readlink() can truncate. The components SNAP_MOUNT_DIR, base_snap_name and revision should keep it from doing so, but you can also simply check if 'base_snap_rev[sizeof base_snap_rev - 1] != '\0' and die(). This way you don't have to worry about assumptions changing down the line.
| + // consideration of the mie->root component. | ||
| + dev_t base_snap_dev = 0; | ||
| + { | ||
| + char base_squashfs_path[PATH_MAX]; |
zyga
Oct 4, 2017
Contributor
Yes, I was thinking the same thing. I just wanted to show the initial code to get quick evaluation before I started messing with it more closely.
zyga
added some commits
Oct 5, 2017
mvo5
reviewed
Oct 5, 2017
Thanks for working on this! Nice progress, one question about die()ing though.
| + const char *base_snap_rev) | ||
| +{ | ||
| + // Find the backing device of the base snap. | ||
| + // TODO: add support for "try mode" base snaps that also need |
mvo5
Oct 5, 2017
Collaborator
Hm, if try mode does not work with this function and we die() below on not-found, isn't that dangerous? I.e. should we just keep going if we cannot find the base snaps dev_t?
zyga
Oct 5, 2017
Contributor
It will not die but it will find the block device for the (typically) home partition. What I mean by this is that we want to remember which directory of that block device was used so that when you do this, it still detects the staleness:
cd ~/foo/base
snap try
cd ~/bar/base
snap try
niemeyer
approved these changes
Oct 10, 2017
A few trivial remarks, but LGTM overall.
Glad to see this moving forward. Thanks!
| + struct sc_mountinfo_entry *mie; | ||
| + struct sc_mountinfo *mi SC_CLEANUP(sc_cleanup_mountinfo) = NULL; | ||
| + | ||
| + mi = sc_parse_mountinfo(NULL); |
niemeyer
Oct 10, 2017
Contributor
If we need to reuse the info, let's hand it in from the outside instead of parsing it on every leaf function.
zyga
Oct 16, 2017
Contributor
We're not parsing mountinfo in any vicinity to this code but I'll do a review of when we do parse it and if we could save some calls. I'll do this in a separate PR though.
| + if (ns_statfs_buf.f_type == NSFS_MAGIC | ||
| + || ns_statfs_buf.f_type == PROC_SUPER_MAGIC) { | ||
| + char fname[PATH_MAX] = { 0, }; | ||
| + char base_snap_rev[PATH_MAX] = { 0, }; |
niemeyer
Oct 10, 2017
Contributor
Why the syntax initializing these to a zero first entry here? We don't do that in the change above. What's the overall convention for snap-confine, and what's the rationale behind it?
zyga
Oct 10, 2017
Contributor
This is a new thing that @jdstrand has requested that we do. I'll do a pass to ensure all the buffers are zero-initialized so that we have consistency.
| + if (readlink(fname, base_snap_rev, sizeof base_snap_rev) < 0) { | ||
| + die("cannot read symlink %s", fname); | ||
| + } | ||
| + if (base_snap_rev[sizeof base_snap_rev - 1] != '\0') { |
niemeyer
Oct 10, 2017
Contributor
Where is this array being initialized to all zeros? Are we using some compiler flag to do that?
zyga
Oct 10, 2017
Contributor
This is what the char base_snap_rev[PATH_MAX] = {0, } does. If there is any explicit initialisation then all other elements are implicitly initialised to zero.
| + die("cannot read symlink %s", fname); | ||
| + } | ||
| + if (base_snap_rev[sizeof base_snap_rev - 1] != '\0') { | ||
| + die("readlink truncated"); |
niemeyer
Oct 10, 2017
Contributor
The fact readlink truncated says absolutely nothing to a user or even to a developer. That's how we end up with those very awkward messages showing up in logs and in the terminal. Let's please be careful to have nice user-oriented error messages at all times.
| + | ||
| + bool should_discard_ns = | ||
| + should_discard_current_ns(base_snap_dev); | ||
| + debug("should the namespace be discarded: %s", |
niemeyer
Oct 10, 2017
Contributor
Also a very vague message, and curious wording too.
Note that "namespace" will provide zero hints of what this is really about even to developers that understand in depth the ideas we're dealing with here.
Instead this could be something like:
if (should_discard_ns) {
debug("discarding obsolete base filesystem namespace")
}
zyga
Oct 10, 2017
Contributor
Ah, sorry, this is just a temporary measure before the rest of this feature is present. I'll update this too.
zyga
added some commits
Oct 16, 2017
| - if (buf.f_type == NSFS_MAGIC || buf.f_type == PROC_SUPER_MAGIC) { | ||
| + if (ns_statfs_buf.f_type == NSFS_MAGIC | ||
| + || ns_statfs_buf.f_type == PROC_SUPER_MAGIC) { | ||
| + char fname[PATH_MAX] = { 0, }; |
mvo5
Oct 18, 2017
Collaborator
Gustavo asked in the other PR that we use { 0 } as the convention. Maybe update it here as well for consistency? Or we can do a followup, I would like to merge this one actually :)
zyga commentedOct 3, 2017
This patch adds detection of stale mount namespaces. This is 1/3 of
the required code, as we also need the code that checks if it is safe to
discard a stale namespace as well as code that actually performs the
discard (all somewhat tricky due to apparmor issues).
The detection logic is simple. We know which base snap we would like to
use and we measure it's major:minor device numbers. We then jump into an
existing namespace and measure the major:minor numbers of the device
backing the root filesystem. If they are different then the mount
namespace is stale.
The next branches will bring in detection of stale and unused
namespace, thanks to soon-landing freezer cgroup code.
Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com
Thanks for helping us make a better snapd!
Have you signed the license agreement and read the contribution guide?